Cómo: Cree y use las instancias del weak_ptr
A veces un objeto debe almacenar una forma de obtener acceso al objeto subyacente de un shared_ptr sin que se produzca el recuento de referencias se incrementa.Normalmente, esta situación se produce cuando tienen referencias cíclicas entre shared_ptr las instancias.
El mejor diseño es evitar una propiedad compartida de punteros siempre que pueda.Sin embargo, si debe compartir la propiedad de shared_ptr las instancias, evitar referencias cíclicas entre ellos.Cuando las referencias cíclicas son inevitables, o incluso preferible por alguna razón, utilice weak_ptr darle una débil uno o varios de los propietarios de la referencia a otro shared_ptr.Mediante el uso de un weak_ptr, puede crear un shared_ptr que se une a un conjunto existente de instancias relacionadas, pero sólo si el recurso de memoria subyacente sigue siendo válido.A weak_ptr no participar en el recuento de referencias y, por lo tanto, no se impide que el recuento de referencia van a cero.Sin embargo, puede utilizar un weak_ptr para intentar obtener una copia nueva de la shared_ptr con que se ha inicializado.Si ya se ha eliminado la memoria, un bad_weak_ptr se produce la excepción.Si la memoria sigue siendo válida, el nuevo puntero compartido aumenta el recuento de referencia y garantiza que la memoria será válida mientras el shared_ptr variable permanece en el ámbito.
Ejemplo
En el ejemplo de código siguiente se muestra un caso donde weak_ptr se utiliza para garantizar la correcta eliminación de objetos que tienen dependencias circulares.Al examinar en el ejemplo, se supone que se creó después de que se tuvieron en cuenta las soluciones alternativas.El Controller objetos representan algún aspecto de un proceso de máquina y funcionan de forma independiente.Cada controlador debe ser capaz de consultar el estado de los controladores de otros en cualquier momento, y cada uno de ellos contiene un privado vector<weak_ptr<Controller>> para este propósito.Cada vector contiene una referencia circular y por lo tanto, weak_ptr las instancias se utilizan en lugar de shared_ptr.
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Controller
{
public:
int Num;
wstring Status;
vector<weak_ptr< Controller >> others;
explicit Controller(int i) : Num(i) , Status(L"On")
{
wcout << L"Creating Controller" << Num << endl;
}
~Controller()
{
wcout << L"Destroying Controller" << Num << endl;
}
// Demonstrates how to test whether the
// pointed-to memory still exists or not.
void CheckStatuses() const
{
for_each(others.begin(), others.end(), [] (weak_ptr<Controller> wp)
{
try
{
auto p = wp.lock();
wcout << L"Status of " << p->Num << " = " << p->Status << endl;
}
catch (bad_weak_ptr b)
{
wcout << L"Null object" << endl;
}
});
}
};
void RunTest()
{
vector<shared_ptr< Controller >> v;
v.push_back(shared_ptr< Controller >(new Controller(0)));
v.push_back(shared_ptr< Controller > (new Controller(1)));
v.push_back(shared_ptr< Controller > (new Controller(2)));
v.push_back(shared_ptr< Controller > (new Controller(3)));
v.push_back(shared_ptr< Controller > (new Controller(4)));
// Each controller depends on all others not being deleted.
// Give each controller a pointer to all the others.
for (int i = 0 ; i < v.size(); i++)
{
for_each(v.begin(), v.end(), [v,i] (shared_ptr<Controller> p)
{
if(p->Num != i)
{
v[i]->others.push_back(weak_ptr<Controller>(p));
wcout << L"push_back to v[" << i << "]: " << p->Num << endl;
}
});
}
for_each(v.begin(), v.end(), [](shared_ptr<Controller>& p)
{
wcout << L"use_count = " << p.use_count() << endl;
p->CheckStatuses();
});
}
int main()
{
RunTest();
wcout << L"Press any key" << endl;
char ch;
cin.getline(&ch, 1);
}
Como experimento, modifique el vector de others sea un vector<shared_ptr<Controller>>y, a continuación, en la salida, observe que no los destructores se invocan cuando TestRun devuelve.