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.
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) |
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.
|
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
|
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
Véase también
(C++11) |
Puntero inteligente con semántica de posesión de objeto compartida. (plantilla de clase) |