Namespaces
Variants

std:: enable_shared_from_this

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
Definido en el encabezado <memory>
template < class T >
class enable_shared_from_this ;
(desde C++11)

std::enable_shared_from_this permite que un objeto t que está actualmente gestionado por un std::shared_ptr llamado pt pueda generar de forma segura instancias adicionales de std::shared_ptr como pt1 , pt2 etc., que compartan la propiedad de t con pt .

Heredar públicamente de std::enable_shared_from_this<T> proporciona al tipo T una función miembro shared_from_this . Si un objeto t de tipo T está gestionado por un std:: shared_ptr < T > llamado pt , entonces llamar a T::shared_from_this devolverá un nuevo std:: shared_ptr < T > que comparte la propiedad de t con pt .

Contenidos

Miembros de datos

Miembro Descripción
mutable std:: weak_ptr < T > weak_this el objeto que rastrea el bloque de control del primer propietario compartido de * this
( objeto miembro solo para exposición* )

Funciones miembro

construye un objeto enable_shared_from_this
(función miembro protegida)
destruye un objeto enable_shared_from_this
(función miembro protegida)
devuelve una referencia a * this
(función miembro protegida)
devuelve un std::shared_ptr que comparte la propiedad de * this
(función miembro pública)
devuelve un std::weak_ptr que comparte la propiedad de * this
(función miembro pública)

Notas

Los constructores de std::shared_ptr detectan la presencia de una base enable_shared_from_this inequívoca y accesible (es decir, la herencia pública es obligatoria) y asignan el recién creado std::shared_ptr a weak_this si aún no está en posesión de un std::shared_ptr activo. Construir un std::shared_ptr para un objeto que ya está gestionado por otro std::shared_ptr no consultará weak_this y por lo tanto conducirá a un comportamiento indefinido.

Se permite llamar a shared_from_this solo en un objeto previamente compartido, es decir, en un objeto gestionado por std:: shared_ptr < T > . De lo contrario, std::bad_weak_ptr es lanzada (por el constructor de std::shared_ptr desde un weak_this construido por defecto).

enable_shared_from_this proporciona la alternativa segura a una expresión como std:: shared_ptr < T > ( this ) , que probablemente resulte en que this sea destruido más de una vez por múltiples propietarios que no son conscientes unos de otros (ver ejemplo abajo).

Ejemplo

#include <iostream>
#include <memory>
class Good : public std::enable_shared_from_this<Good>
{
public:
    std::shared_ptr<Good> getptr()
    {
        return shared_from_this();
    }
};
class Best : public std::enable_shared_from_this<Best>
{
    struct Private{ explicit Private() = default; };
public:
    // El constructor solo es utilizable por esta clase
    Best(Private) {}
    // Todos los demás deben usar esta función de fábrica
    // Por lo tanto, todos los objetos Best estarán contenidos en shared_ptr
    static std::shared_ptr<Best> create()
    {
        return std::make_shared<Best>(Private());
    }
    std::shared_ptr<Best> getptr()
    {
        return shared_from_this();
    }
};
struct Bad
{
    std::shared_ptr<Bad> getptr()
    {
        return std::shared_ptr<Bad>(this);
    }
    ~Bad() { std::cout << "Bad::~Bad() called\n"; }
};
void testGood()
{
    // Bueno: los dos shared_ptr comparten el mismo objeto
    std::shared_ptr<Good> good0 = std::make_shared<Good>();
    std::shared_ptr<Good> good1 = good0->getptr();
    std::cout << "good1.use_count() = " << good1.use_count() << '\n';
}
void misuseGood()
{
    // Malo: se llama a shared_from_this sin que std::shared_ptr sea propietario del llamador
    try
    {
        Good not_so_good;
        std::shared_ptr<Good> gp1 = not_so_good.getptr();
    }
    catch (std::bad_weak_ptr& e)
    {
        // comportamiento indefinido (hasta C++17) y std::bad_weak_ptr lanzado (desde C++17)
        std::cout << e.what() << '\n';
    }
}
void testBest()
{
    // Mejor: Igual pero no se puede asignar en la pila:
    std::shared_ptr<Best> best0 = Best::create();
    std::shared_ptr<Best> best1 = best0->getptr();
    std::cout << "best1.use_count() = " << best1.use_count() << '\n';
    // Best stackBest; // <- No compilará porque Best::Best() es privado.
}
void testBad()
{
    // Malo: cada shared_ptr cree que es el único propietario del objeto
    std::shared_ptr<Bad> bad0 = std::make_shared<Bad>();
    std::shared_ptr<Bad> bad1 = bad0->getptr();
    std::cout << "bad1.use_count() = " << bad1.use_count() << '\n';
} // Comportamiento indefinido: doble eliminación de Bad
int main()
{
    testGood();
    misuseGood();
    testBest();
    testBad();
}

Salida posible:

good1.use_count() = 2
bad_weak_ptr
best1.use_count() = 2
bad1.use_count() = 1
Bad::~Bad() llamado
Bad::~Bad() llamado
*** glibc detectado *** ./test: doble liberación o corrupción

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Se aplica a Comportamiento publicado Comportamiento correcto
LWG 2179
( P0033R1 )
C++11 dado un tipo T derivado de enable_shared_from_this , el comportamiento de
construir dos std:: shared_ptr < T > desde el mismo objeto T * no estaba claro
el comportamiento es
indefinido en este caso
LWG 2529
( P0033R1 )
C++11 no estaba claro cómo se actualiza el std::weak_ptr subyacente aclarado

Véase también

(C++11)
puntero inteligente con semántica de propiedad compartida de objetos
(plantilla de clase)
crea un shared pointer que gestiona un nuevo objeto
(plantilla de función)