std::enable_shared_from_this
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) | |
(C++17) |
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
(C++11) |
Puntero inteligente con semántica de posesión de objeto compartida. (plantilla de clase) |