Procédure : Créer et utiliser des instances weak_ptr
Parfois, un objet doit stocker un moyen d’accéder à l’objet sous-jacent d’une shared_ptr sans entraîner l’incrémentation du nombre de références. En règle générale, cette situation se produit lorsque vous avez des références cycliques entre shared_ptr
des instances.
La meilleure conception consiste à éviter la propriété partagée des pointeurs chaque fois que vous le pouvez. Toutefois, si vous devez avoir la propriété partagée des shared_ptr
instances, évitez les références cycliques entre elles. Lorsque les références cycliques sont inévitables, voire préférables pour une raison quelconque, utilisez weak_ptr pour donner une ou plusieurs des propriétaires une référence faible à une autre shared_ptr
. À l’aide d’un weak_ptr
, vous pouvez créer une shared_ptr
jointure à un ensemble existant d’instances associées, mais uniquement si la ressource de mémoire sous-jacente est toujours valide. Un weak_ptr
lui-même ne participe pas au comptage de références, et par conséquent, il ne peut pas empêcher le nombre de références d’aller à zéro. Toutefois, vous pouvez utiliser un weak_ptr
outil pour essayer d’obtenir une nouvelle copie du shared_ptr
fichier avec lequel il a été initialisé. Si la mémoire a déjà été supprimée, l’opérateur weak_ptr
bool 's bool retourne false
. Si la mémoire est toujours valide, le nouveau pointeur partagé incrémente le nombre de références et garantit que la mémoire sera valide tant que la variable reste dans l’étendue shared_ptr
.
Exemple
L’exemple de code suivant montre un cas où weak_ptr
est utilisé pour garantir la suppression appropriée d’objets qui ont des dépendances circulaires. Comme vous examinez l’exemple, supposons qu’il a été créé uniquement après que d’autres solutions ont été prises en compte. Les Controller
objets représentent un aspect d’un processus machine et fonctionnent indépendamment. Chaque contrôleur doit être en mesure d’interroger l’état des autres contrôleurs à tout moment, et chacun d’eux contient un privé 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) {
auto p = wp.lock();
if (p)
{
wcout << L"Status of " << p->Num << " = " << p->Status << endl;
}
else
{
wcout << L"Null object" << endl;
}
});
}
};
void RunTest()
{
vector<shared_ptr<Controller>> v{
make_shared<Controller>(0),
make_shared<Controller>(1),
make_shared<Controller>(2),
make_shared<Controller>(3),
make_shared<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);
}
Creating Controller0
Creating Controller1
Creating Controller2
Creating Controller3
Creating Controller4
push_back to v[0]: 1
push_back to v[0]: 2
push_back to v[0]: 3
push_back to v[0]: 4
push_back to v[1]: 0
push_back to v[1]: 2
push_back to v[1]: 3
push_back to v[1]: 4
push_back to v[2]: 0
push_back to v[2]: 1
push_back to v[2]: 3
push_back to v[2]: 4
push_back to v[3]: 0
push_back to v[3]: 1
push_back to v[3]: 2
push_back to v[3]: 4
push_back to v[4]: 0
push_back to v[4]: 1
push_back to v[4]: 2
push_back to v[4]: 3
use_count = 1
Status of 1 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 2 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 3 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 4 = On
use_count = 1
Status of 0 = On
Status of 1 = On
Status of 2 = On
Status of 3 = On
Destroying Controller0
Destroying Controller1
Destroying Controller2
Destroying Controller3
Destroying Controller4
Press any key
En tant qu’expérience, modifiez le vecteur others
pour qu’il soit un vector<shared_ptr<Controller>>
, puis dans la sortie, notez qu’aucun destructeur n’est appelé quand il RunTest
est retourné.
Voir aussi
Commentaires
https://aka.ms/ContentUserFeedback.
Bientôt disponible : Tout au long de 2024, nous allons supprimer progressivement GitHub Issues comme mécanisme de commentaires pour le contenu et le remplacer par un nouveau système de commentaires. Pour plus d’informations, consultezEnvoyer et afficher des commentaires pour