del artículo del Dr. Dobbs sobre punteros débiles, creo que este ejemplo es más fácil de entender (fuente: http://drdobbs.com/cpp/184402026 ):
... un código como este no funcionará correctamente:
int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);
Ninguno de los dos shared_ptr
objetos conoce al otro, por lo que ambos intentarán liberar el recurso cuando sean destruidos. Eso generalmente lleva a problemas.
Del mismo modo, si una función miembro necesita un shared_ptr
objeto que posee el objeto al que se está llamando, no puede crear un objeto sobre la marcha:
struct S
{
shared_ptr<S> dangerous()
{
return shared_ptr<S>(this); // don't do this!
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->dangerous();
return 0;
}
Este código tiene el mismo problema que el ejemplo anterior, aunque en una forma más sutil. Cuando se construye, el shared_pt
objeto r sp1
posee el recurso recién asignado. El código dentro de la función miembro S::dangerous
no conoce ese shared_ptr
objeto, por lo que el shared_ptr
objeto que devuelve es distinto sp1
. Copiar el nuevo shared_ptr
objeto a sp2
no ayuda; cuando está sp2
fuera de alcance, liberará el recurso, y cuando sp1
salga del alcance, volverá a liberar el recurso.
La forma de evitar este problema es usar la plantilla de clase enable_shared_from_this
. La plantilla toma un argumento de tipo de plantilla, que es el nombre de la clase que define el recurso administrado. Esa clase debe, a su vez, derivarse públicamente de la plantilla; Me gusta esto:
struct S : enable_shared_from_this<S>
{
shared_ptr<S> not_dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->not_dangerous();
return 0;
}
Cuando haga esto, tenga en cuenta que el objeto al que llama shared_from_this
debe ser propiedad de un shared_ptr
objeto. Esto no funcionará:
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->not_dangerous(); // don't do this
}
std::shared_ptr
constructor en un puntero sin formato si hereda destd::enable_shared_from_this
. No sé si la semántica de Boost se actualizó para respaldar esto.std::shared_ptr
un objeto que ya está administrado por otrostd::shared_ptr
no consultará la referencia débil almacenada internamente y, por lo tanto, conducirá a un comportamiento indefinido". ( en.cppreference.com/w/cpp/memory/enable_shared_from_this )shared_ptr<Y> q = p
?std::make_shared<T>
.