¿Cuál es la diferencia entre un std::shared ptr vacío y un null en C++?


El cplusplus.com shared_ptr página llamadas a cabo una distinción entre un vacío std::shared_ptr y un null shared_ptr. El cppreference.com page no menciona explícitamente la distinción, pero usa tanto "vacío" como la comparación con nullptr en su descripción del comportamiento de std::shared_ptr.

Hay una diferencia entre un vacío y un nulo shared_ptr? ¿Hay algún caso de uso para tales punteros de comportamiento mixto? ¿Tiene sentido un null no vacío shared_ptr? ¿Habría alguna vez un caso en uso normal (es decir, si no construiste explícitamente uno) donde podrías terminar con un shared_ptr vacío pero no nulo?

¿Y alguna de estas respuestas cambia si está utilizando la versión de Boost en lugar de la versión de C++11?

Author: Niall, 2014-09-18

2 answers

Es un rincón extraño del comportamiento shared_ptr. Tiene un constructor que le permite hacer un shared_ptr que posee algo y apunta a algo más:

template< class Y > 
shared_ptr( const shared_ptr<Y>& r, T *ptr );

El shared_ptr construido usando este constructor comparte la propiedad con r, pero apunta a lo que ptr señala (es decir, llamando get() o operator->() devolverá ptr). Esto es útil para los casos en los que ptr apunta a un subobjeto (por ejemplo, un miembro de datos) del objeto propiedad de r.

La página que vinculó llama a un shared_ptr que no posee nada vacío , y a un shared_ptr que no apunta a nada (es decir, cuya get() == nullptr) null . ( Emptyse usa en este sentido por el estándar; null no lo es.) Puede construir un null-but-not-empty shared_ptr, pero no será muy útil. Un shared_ptr vacío pero no nulo es esencialmente un puntero no propietario, que se puede usar para hacer algunas cosas extrañas como pasar un puntero a algo asignado en la pila a una función que espera un shared_ptr (pero yo sugeriría golpear a quien puso shared_ptr dentro de la API primero).

boost::shared_ptr también tiene este constructor, al que llaman el constructor aliasing.

 73
Author: T.C.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:31

hay una diferencia entre un vacío y un nulo shared_ptr?

Empty shared_ptr no tiene bloque de control y su número de uso se considera 0. Una copia de empty shared_ptr es otra vacía shared_ptr. Ambos son shared_ptrs separados que no comparten bloque de control común porque no lo tienen. Empty shared_ptr se puede construir con el constructor predeterminado o con el constructor que toma nullptr.

Null no vacío shared_ptr tiene un bloque de control que se puede compartir con otros shared_ptr s. Copy of non-empty null shared_ptr is shared_ptr that shares the same control block as original shared_ptr so use count is not 0. Se puede decir que todas las copias de shared_ptr comparten lo mismo nullptr. Null no vacío shared_ptr se puede construir con puntero nulo del tipo de objeto (no nullptr)

Aquí está el ejemplo:

#include <iostream>
#include <memory>

int main()
{
    std::cout << "std::shared_ptr<int> ptr1:" << std::endl;
    {
        std::shared_ptr<int> ptr1;
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    std::cout << "std::shared_ptr<int> ptr1(nullptr):" << std::endl;
    {
        std::shared_ptr<int> ptr1(nullptr);
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    std::cout << "std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))" << std::endl;
    {
        std::shared_ptr<int> ptr1(static_cast<int*>(nullptr));
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    return 0;
}

Produce:

std::shared_ptr<int> ptr1:
    use count before copying ptr: 0
    use count  after copying ptr: 0
    ptr1 is null

std::shared_ptr<int> ptr1(nullptr):
    use count before copying ptr: 0
    use count  after copying ptr: 0
    ptr1 is null

std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))
    use count before copying ptr: 1
    use count  after copying ptr: 2
    ptr1 is null

Http://coliru.stacked-crooked.com/a/54f59730905ed2ff

 4
Author: anton_rh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-16 12:04:46