Espacios de nombres
Variantes
Acciones

std::enable_shared_from_this

De cppreference.com
< cpp‎ | memory
 
 
Biblioteca de servicios
 
Gestión de memoria dinámica
Punteros inteligentes
(C++11)
(C++11)
(C++11)
(hasta C++17)
(C++11)
enable_shared_from_this
(C++11)
(C++23)
Asignadores de memoria
Recursos de memoria
Almacenamiento no inicializado
Algoritmos de memoria no inicializada
Algoritmos restringidos de memoria no inicializada
Apoyo para recolección de basura
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
(C++11)(hasta C++23)
Misceláneos
(C++20)
(C++11)
(C++11)
 
 
Definido en el archivo de encabezado <memory>
template< class T > class enable_shared_from_this;
(desde C++11)

std::enable_shared_from_this permite que un objeto t que actualmente está gestionado por un std::shared_ptr llamado pt genere de forma segura instancias de std::shared_ptr pt1, pt2, ... que compartan la posesión de t con pt.

La herencia pública de std::enable_shared_from_this<T> proporciona el tipo T con una función miembro shared_from_this. Si un objeto t de tipo T es 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 posesión de t con pt.

Contenido

[editar] 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 shared_ptr que comparte la posesión de *this
(función miembro pública)
Devuelve el weak_ptr que comparte la posesión de *this
(función miembro pública)

[editar] Objetos miembro

Nombre del miembro Definición
weak_this (privado)(C++17) Objeto std::weak_ptr que rastrea el bloque de control del primer dueño compartido de *this. Solo de exposición.

[editar] Notas

Una implementación común para enable_shared_from_this es mantener una referencia débil (como std::weak_ptr) a this. Los constructores de std::shared_ptr detectan la presencia de una base enable_shared_from_this no ambigua y accesible (es decir, la herencia pública es obligatoria) (desde C++17) y asignan el std::shared_ptr recién creado a la referencia débil almacenada internamente si aún no es posesión de un std::shared_ptr vivo (desde C++17). Construir un std::shared_ptr para un objeto que ya está gestionado por otro std::shared_ptr no consultará la referencia débil almacenada internamente y, por lo tanto, conducirá a un comportamiento no definido.

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 el comportamiento no está definido se lanza std::bad_weak_ptr (por el constructor shared_ptr de un weak_this) (desde C++17) 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 la destrucción de this más de una vez por varios poseedores que no se conocen entre sí (ver el ejemplo a continuación).


Macro de Prueba de característica
__cpp_lib_enable_shared_from_this

[editar] Ejemplo

#include <memory>
#include <iostream>
 
struct Good : std::enable_shared_from_this<Good> // nota: herencia pública
{
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
};
 
struct Best : std::enable_shared_from_this<Best> // nota: herencia pública
{
    std::shared_ptr<Best> getptr() {
        return shared_from_this();
    }
    // No hay un constructor público, solo una función fábrica,
    // así que no hay manera de que getptr devuelva nullptr.
    [[nodiscard]] static std::shared_ptr<Best> create() {
        // No se usa std::make_shared<Best> porque el ctor es privado.
        return std::shared_ptr<Best>(new Best());
    }
private:
    Best() = default;
};
 
 
struct Bad
{
    std::shared_ptr<Bad> getptr() {
        return std::shared_ptr<Bad>(this);
    }
    ~Bad() { std::cout << "Se llamó a Bad::~Bad()\n"; }
};
 
void testGood()
{
    // Bueno: los dos two 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: shared_from_this se llama sin que std::shared_ptr posea al llamante 
    try {
        Good not_so_good;
        std::shared_ptr<Good> gp1 = not_so_good.getptr();
    } catch(std::bad_weak_ptr& e) {
        // comportamiento no definido (hasta C++17) y se lanza std::bad_weak_ptr (desde C++17)
        std::cout << e.what() << '\n';    
    }
}
 
 
void testBest()
{
    // Lo mejor: Lo mismo, 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 piensa que es el único dueño 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 no definido: doble eliminación de Bad
 
 
int main()
{
    testGood();
    misuseGood();
 
    testBest();
 
    testBad();
}

Posible salida:

good1.use_count() = 2
bad_weak_ptr
best1.use_count() = 2
bad1.use_count() = 1
Se llamó a Bad::~Bad()
Se llamó a Bad::~Bad()
*** glibc detected *** ./test: doble liberación of corrupción

[editar] Véase también

Puntero inteligente con semántica de posesión de objeto compartida.
(plantilla de clase) [editar]