88 votes

différences shared_ptr et faible_ptr

Je suis à la lecture de Scott Meyers "Effective C++" livre. Il a été mentionné qu'il y a tr1::shared_ptr et tr1::weak_ptr agir comme intégré dans les indicateurs, mais ils gardent une trace de combien de tr1::shared_ptrs point à un objet.

Ceci est connu comme le comptage de référence. Cela fonctionne bien dans la prévention des fuites de ressource dans acyclique, structures de données, mais si deux ou plusieurs objets contiennent tr1::shared_ptrs tel qu'un cycle est formé, le cycle peut se tenir de compte de référence au-dessus de zéro, même lorsque tous les pointeurs du cycle ont été détruits.

C'est là que tr1::weak_ptrs venir.

Ma question est comment cyclique des structures de données de rendre compte de référence au-dessus de zéro, de bien vouloir nous demande de montrer l'exemple dans un programme C++. Comment le problème est résolu en wear_ptrs nouveau avec exemple s'il vous plaît.

136voto

Atom Points 8739

Permettez-moi de répéter votre question: "Ma question, comment cyclique des structures de données rend compte de référence au-dessus de zéro, de bien vouloir nous demande de montrer l'exemple dans un programme C++. Comment le problème est résolu en weak_ptrs nouveau avec exemple s'il vous plaît."

Le problème se produit avec le code C++ comme ceci (conceptuellement):

class A { shared_ptr<B> b; ... };
class B { shared_ptr<A> a; ... };
shared_ptr<A> x(new A);  // +1
x->b = new B;            // +1
x->b->a = x;             // +1
// Ref count of 'x' is 2.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, there will be a memory leak:
// 2 is decremented to 1, and so both ref counts will be 1.
// (Memory is deallocated only when ref count drops to 0)

Pour répondre à la deuxième partie de votre question: Il est mathématiquement impossible pour le comptage de référence pour traiter avec les cycles. Par conséquent, un weak_ptr (ce qui est fondamentalement juste une version allégée de l' shared_ptr) ne peuvent pas être utilisées pour résoudre le cycle de problème - le programmeur est la résolution du cycle de problème.

Pour le résoudre, le programmeur doit être conscient de la propriété de la relation entre les objets, ou les besoins d'inventer une propriété de la relation si pas de ce droit de propriété existe naturellement.

Ci-dessus le code C++ peut être modifié de sorte qu'Un propriétaire de B:

class A { shared_ptr<B> b; ... };
class B { weak_ptr<A>   a; ... };
shared_ptr<A> x(new A); // +1
x->b = new B;           // +1
x->b->a = x;            // No +1 here
// Ref count of 'x' is 1.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, its ref count will drop to 0.
// While destroying it, ref count of 'x->b' will drop to 0.
// So both A and B will be deallocated.

Une question cruciale est: Peut - weak_ptr être utilisé dans le cas où le programmeur ne peut pas dire la propriété de la relation et ne peut pas établir de l'électricité statique à la propriété en raison de l'absence de privilège ou de manque d'information?

La réponse est: Si la propriété parmi les objets n'est pas clair, weak_ptr ne peut pas aider. Si il y a un cycle, le programmeur a le trouver et de le briser. Une autre solution est d'utiliser un langage de programmation avec plein de collecte des ordures (tels que: Java, C#, Allez, Haskell), ou l'utilisation d'un conservateur (=imparfait) garbage collector qui travaille avec C/C++ (comme: Boehm GC).

66voto

doron Points 10296

Un shared_ptr encapsule un mécanisme de calcul de référence autour d'un pointeur brut. Donc, pour chaque instance de l' shared_ptr le nombre de références est augmenté de un. Si deux share_ptr objets font référence à l'eachother, ils ne seront jamais supprimés car ils ne pourront jamais retrouver avec un nombre de référence zéro.

weak_ptr de points à un shared_ptr mais n'augmente pas son compte de référence.Cela signifie que le underying objet peut toujours être supprimées, même si il y a un weak_ptr référence.

La façon dont cela fonctionne est que l' weak_ptr peut être utiliser pour créer un shared_ptr pour chaque fois que l'on veut utiliser l'objet sous-jacent. Toutefois, si l'objet a déjà été supprimés alors un vide instance d'un shared_ptr est retourné. Depuis le nombre de références sur l'objet sous-jacent n'est pas augmentée avec un weak_ptr de référence, une référence circulaire n'entraînera pas l'objet sous-jacent n'étant pas supprimé.

21voto

newprint Points 1205

Pour les futurs lecteurs.
Je veux juste souligner que l'explication donnée par Atom est excellente, voici le code de travail

 #include <memory> // and others
using namespace std;

    class B; // forward declaration 
    // for clarity, add explicit destructor to see that they are not called
    class A { public: shared_ptr<B> b; ~A() {cout << "~A()" << endl; } };  
    class B { public: shared_ptr<A> a; ~B() {cout << "~B()" << endl; } };     
    shared_ptr<A> x(new A);  //x->b share_ptr is default initialized
    x->b = make_shared<B>(); // you can't do "= new B" on shared_ptr                      
    x->b->a = x;
    cout << x.use_count() << endl;  
 

9voto

peterDriscoll Points 9

Des pointeurs faibles juste "d'observer" l'objet géré; ils ne sont pas "maintenir en vie" ou d'affecter sa durée de vie. Contrairement à shared_ptrs, lors de la dernière weak est hors de portée ou disparaît, la pointe-à objet peut encore exister que parce que le weak_ptrs ne pas affecter la durée de vie de l'objet - ils n'ont pas de droits de propriété. Mais le weak peut être utilisé pour déterminer si l'objet existe, et de fournir un shared_ptr qui peut être utilisé pour la désigner. La définition de weak est conçu pour le rendre relativement à toute épreuve, et par conséquent, il ya très peu que vous pouvez faire directement avec un weak. Par exemple, vous ne pouvez pas le déréférencement d'elle, ni de l'opérateur*, ni l'opérateur-> est défini pour un weak. Vous ne pouvez pas accéder au pointeur vers l'objet avec lui - il n'y a pas de get() de la fonction. Il y a un fonction de comparaison définie, de sorte que vous pouvez stocker weak_ptrs dans un ensemble ordonné conteneur; mais c'est tout.

-9voto

Earth Engine Points 1795

Tous la réponse ci-dessus sont fausses. weak_ptr n'est PAS utilisée pour briser les références cycliques, ils ont d'autres but.

En gros, si tous shared_ptr(s) ont été créés par make_shared() ou allocate_shared() des appels, vous n'aurez plus JAMAIS besoin d' weak_ptr si vous n'avez pas de ressources autres que de mémoire pour gérer. Ces fonctions crée l' shared_ptr compteur de référence de l'objet avec l'objet lui-même, et la mémoire sera libérée en même temps.

La seule différence entre weak_ptr et shared_ptr , c'est que l' weak_ptr permet le compteur de référence de l'objet à être conservés après l'objet réel a été libéré. Par conséquent, si vous conservez un grand nombre d' shared_ptr en std::set des objets réels occupera beaucoup de mémoire si elles sont suffisamment grandes. Ce problème peut être résolu en utilisant weak_ptr à la place. Dans ce cas, vous devez vous assurer de l' weak_ptr stockés dans le conteneur n'est pas expiré avant de l'utiliser.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X