Como: criar e usar instâncias weak_ptr
Às vezes, um objeto deve armazenar uma maneira de acessar o objeto subjacente de um shared_ptr sem causar a contagem de referência ser incrementada.Normalmente, esta situação ocorre quando você tem referências cíclicas entre shared_ptr instâncias.
O melhor design é evitar propriedade compartilhada de ponteiros sempre que puder.No entanto, se você deve ter compartilhado apropriar shared_ptr instâncias, evite referências cíclicas entre elas.Quando referências cíclicas são inevitáveis, ou até mesmo preferível por algum motivo, use weak_ptr para dar um ou mais proprietários um fraco referência a outro shared_ptr.Usando um weak_ptr, você pode criar um shared_ptr que associa um conjunto existente de instâncias relacionadas, mas somente se o recurso de memória subjacente ainda é válido.A weak_ptr si não participa de contagem de referência e, portanto, ele não pode impedir a contagem de referência for zero.No entanto, você pode usar um weak_ptr para tentar obter uma nova cópia do shared_ptr com o qual ele foi inicializado.Se a memória já tiver sido excluída, um bad_weak_ptr exceção é lançada.Se a memória ainda é válida, o novo ponteiro compartilhado incrementa a contagem de referência e garante que a memória será válida desde que o shared_ptr variável permanece em escopo.
Exemplo
O exemplo de código a seguir mostra um caso onde weak_ptr é usado para garantir a correta exclusão de objetos que possuem dependências circulares.Como examinar o exemplo, suponha que foi criado depois de soluções alternativas foram consideradas.O Controller objetos representam algum aspecto do processo de máquina e elas operam de forma independente.Cada controlador deve ser capaz de consultar o status dos outros controladores a qualquer momento, e cada um contém um particular vector<weak_ptr<Controller>> para essa finalidade.Cada vetor contém uma referência circular e, portanto, weak_ptr instâncias são usadas em vez 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 exercício, modifique o vetor de others ser um vector<shared_ptr<Controller>>e na saída, observe que nenhuma destrutores são chamados quando TestRun retorna.