Comment : Créer et utiliser les instances de weak_ptr
Parfois un objet doit stocker un moyen pour accéder à l'objet sous-jacent d'un shared_ptr sans provoquer le décompte de références est incrémenté.Cette situation se produit généralement lorsque vous avez des références cycliques entre shared_ptr instances.
La meilleure conception consiste à éviter partagent la propriété de pointeurs quand vous le pouvez.Toutefois, si vous devez avoir partagé approprier shared_ptr instances, éviter les références cycliques entre eux.Lors de références cycliques sont inévitables, ou même préférable pour une raison quelconque, utilisez weak_ptr pour donner à un ou plusieurs des propriétaires une faible référence à un autre shared_ptr.À l'aide d'un weak_ptr, vous pouvez créer un shared_ptr qui se joint à un jeu existant d'instances liées, mais uniquement si la ressource mémoire sous-jacente est toujours valide.A weak_ptr lui-même ne participe pas le décompte de références, et par conséquent, il ne peut pas empêcher le décompte de références de passer à zéro.Toutefois, vous pouvez utiliser un weak_ptr pour tenter d'obtenir une nouvelle copie de la shared_ptr avec lequel il a été initialisé.Si la mémoire a déjà été supprimée, un bad_weak_ptr exception est levée.Si la mémoire est toujours valide, le nouveau pointeur partagé incrémente le décompte de références et garantit que la mémoire sera valide tant que le shared_ptr variable reste dans la portée.
Exemple
L'exemple de code suivant illustre un cas où weak_ptr est utilisée pour garantir la suppression correcte des objets qui ont des dépendances circulaires.En examinant l'exemple, supposons qu'il a été créé qu'après que les solutions alternatives ont été examinées.Le Controller objets représentent certains aspects d'un processus de machine, et ils fonctionnent de façon indépendante.Chaque contrôleur doit être en mesure d'interroger l'état des autres contrôleurs à tout moment, et chacun d'eux contient une private vector<weak_ptr<Controller>> à cet effet.Chaque vecteur contient une référence circulaire et par conséquent, weak_ptr les instances sont utilisées au lieu 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);
}
Par une expérimentation, modifiez le vecteur others pour être un vector<shared_ptr<Controller>>, puis dans la sortie, vous remarquez que sans les destructeurs sont appelés lorsque TestRun renvoie.