std:: enable_shared_from_this
|
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) |
|
|
(C++17)
|
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) |