Procedura: Creare e utilizzare le istanze di weak_ptr
A volte un oggetto necessario memorizzare un modo per accedere all'oggetto sottostante di un shared_ptr senza essere incrementato il conteggio dei riferimenti.In genere, questa situazione si verifica quando si dispone di riferimenti ciclici tra shared_ptr le istanze.
Progettazione ottimale consiste nell'evitare proprietà condivise dei puntatori quando possibile.Tuttavia, se deve essere stata condivisa proprietario di shared_ptr istanze, evitare i riferimenti ciclici tra di essi.Quando i riferimenti ciclici sono inevitabili, o addirittura preferibile per qualche motivo, utilizzare weak_ptr per assegnare uno o più proprietari un debole riferimento a un altro shared_ptr.Utilizzando un weak_ptr, è possibile creare un shared_ptr che viene aggiunto a un insieme esistente di istanze correlate, ma solo se la risorsa di memoria sottostante è ancora valida.A weak_ptr stesso non partecipa il conteggio dei riferimenti e di conseguenza, è possibile impedire il conteggio dei riferimenti a zero.Tuttavia, è possibile utilizzare un weak_ptr per tentare di ottenere una nuova copia del shared_ptr con cui è stato inizializzato.Se la memoria è già stata eliminata, un bad_weak_ptr eccezione viene generata un'eccezione.Se la memoria è ancora valida, il nuovo puntatore condiviso incrementa il conteggio dei riferimenti e garantisce che la memoria sia valida, purché il shared_ptr variabile rimane nell'ambito.
Esempio
Nell'esempio di codice riportato di seguito viene illustrato un caso in cui weak_ptr viene utilizzata per garantire la corretta eliminazione degli oggetti esistono dipendenze circolari.Quando si esamina l'esempio, si supponga che sia stato creato solo dopo che sono state considerate soluzioni alternative.Il Controller gli oggetti rappresentano un aspetto di un processo di computer e possono essere utilizzate in modo indipendente.Ogni controller deve essere in grado di eseguire una query in qualsiasi momento lo stato degli altri controller e ognuno di essi contiene private vector<weak_ptr<Controller>> a questo scopo.Ogni vettore contiene un riferimento circolare e di conseguenza, weak_ptr le istanze vengono utilizzate invece di 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);
}
Come esperimento, modificare il vettore di others da un vector<shared_ptr<Controller>>e quindi si noti che non i distruttori vengono richiamati nell'output, quando TestRun restituisce.