c++ - shared_ptr - unique_ptr




Quand std:: weak_ptr est-il utile? (7)

J'ai commencé à étudier les pointeurs intelligents de C ++ 11 et je ne vois pas l'utilité de std::weak_ptr . Quelqu'un peut-il me dire quand std::weak_ptr est utile / nécessaire?


Ils sont utiles avec Boost.Asio lorsque vous n'êtes pas certain qu'un objet cible existe toujours lorsqu'un gestionnaire asynchrone est appelé. L'astuce consiste à lier un weak_ptr dans l'objet gestionnaire asynchonous, en utilisant des captures std::bind ou lambda.

void MyClass::startTimer()
{
    std::weak_ptr<MyClass> weak = shared_from_this();
    timer_.async_wait( [weak, this](const boost::system::error_code& ec)
    {
        auto self = weak.lock();
        if (self)
        {
            self->handleTimeout();
        }
        else
        {
            std::cout << "Target object no longer exists!\n";
        }
    } );
}

Ceci est une variante de l'idiome self = shared_from_this() souvent vu dans les exemples Boost.Asio, où un gestionnaire asynchrone en attente ne prolongera pas la durée de vie de l'objet cible, mais est toujours sûr si l'objet cible est supprimé.


Le pointeur partagé présente un inconvénient: shared_pointer ne peut pas gérer la dépendance du cycle enfant-parent. Signifie que la classe parent utilise l'objet de la classe enfant à l'aide du pointeur partagé, dans le même fichier si la classe enfant utilise l'objet de la classe parente. Le pointeur partagé ne parvient pas à détruire tous les objets, même le pointeur partagé n'appelle pas du tout le destructeur dans le scénario de dépendance au cycle. pointeur fondamentalement partagé ne supporte pas le mécanisme de comptage de références.

Cet inconvénient que nous pouvons surmonter en utilisant weak_pointer.


Un bon exemple serait un cache.

Pour les objets auxquels vous avez récemment accédé, vous voulez les garder en mémoire, vous devez donc leur indiquer un pointeur fort. Périodiquement, vous analysez le cache et décidez quels objets n'ont pas été accédés récemment. Vous n'avez pas besoin de garder ceux en mémoire, alors vous vous débarrassez du pointeur fort.

Mais que se passe-t-il si cet objet est utilisé et un autre code contient un pointeur fort? Si le cache se débarrasse de son seul pointeur sur l'objet, il ne peut plus le retrouver. Le cache garde donc un pointeur faible vers les objets qu'il doit trouver s'il reste en mémoire.

C'est exactement ce que fait un pointeur faible - il vous permet de localiser un objet s'il est toujours là, mais ne le garde pas si rien d'autre n'en a besoin.


Une autre réponse, espérons-le plus simple. (pour les autres googleurs)

Supposons que vous ayez Member objets Team et Member .

Évidemment, c'est une relation: l'objet Team aura des pointeurs vers ses Members . Et il est probable que les membres auront également un pointeur arrière vers leur objet Team .

Ensuite, vous avez un cycle de dépendance. Si vous utilisez shared_ptr , les objets ne seront plus automatiquement libérés lorsque vous abandonnerez la référence, car ils se référenceront de manière cyclique. C'est une fuite de mémoire.

Vous cassez ceci en utilisant weak_ptr . Le "propriétaire" utilise généralement shared_ptr et le "owned" utilise un weak_ptr à son parent, et le convertit temporairement en shared_ptr lorsqu'il a besoin d'accéder à son parent.

Stocke un faible ptr:

weak_ptr<Parent> parentWeakPtr_ = parentSharedPtr; // automatic conversion to weak from shared

alors utilisez-le au besoin

shared_ptr<Parent> tempParentSharedPtr = parentWeakPtr_.lock(); // on the stack, from the weak ptr
if( not tempParentSharedPtr ) {
  // yes it may failed if parent was freed since we stored weak_ptr
} else {
  // do stuff
}
// tempParentSharedPtr is released when it goes out of scope

http://en.cppreference.com/w/cpp/memory/weak_ptr std :: weak_ptr est un pointeur intelligent qui contient une référence non-propriétaire ("faible") à un objet géré par std :: shared_ptr. Il doit être converti en std :: shared_ptr afin d'accéder à l'objet référencé.

Modèles std :: weak_ptr propriété temporaire: quand un objet a besoin d'être accédé seulement s'il existe, et il peut être supprimé à tout moment par quelqu'un d'autre, std :: weak_ptr est utilisé pour suivre l'objet, et il est converti en std: : shared_ptr pour assumer la propriété temporaire. Si le fichier original std :: shared_ptr est détruit à ce moment, la durée de vie de l'objet est prolongée jusqu'à ce que le fichier temporaire std :: shared_ptr soit également détruit.

De plus, std :: weak_ptr est utilisé pour casser les références circulaires de std :: shared_ptr.


std::weak_ptr est un très bon moyen de résoudre le problème du pointeur qui pend . En utilisant simplement des pointeurs bruts, il est impossible de savoir si les données référencées ont été désallouées ou non. Au lieu de cela, en laissant std::shared_ptr gérer les données et en fournissant std::weak_ptr aux utilisateurs des données, les utilisateurs peuvent vérifier la validité des données en appelant expired() ou lock() .

Vous ne pouvez pas le faire avec std::shared_ptr seul, car toutes les instances de std::shared_ptr partagent la propriété des données qui ne sont pas supprimées avant que toutes les instances de std::shared_ptr soient supprimées. Voici un exemple de vérification du pointeur dangling à l'aide de lock() :

#include <iostream>
#include <memory>

int main()
{
    // OLD, problem with dangling pointer
    // PROBLEM: ref will point to undefined data!

    int* ptr = new int(10);
    int* ref = ptr;
    delete ptr;

    // NEW
    // SOLUTION: check expired() or lock() to determine if pointer is valid

    // empty definition
    std::shared_ptr<int> sptr;

    // takes ownership of pointer
    sptr.reset(new int);
    *sptr = 10;

    // get pointer to data without taking ownership
    std::weak_ptr<int> weak1 = sptr;

    // deletes managed object, acquires new pointer
    sptr.reset(new int);
    *sptr = 5;

    // get pointer to new data without taking ownership
    std::weak_ptr<int> weak2 = sptr;

    // weak1 is expired!
    if(auto tmp = weak1.lock())
        std::cout << *tmp << '\n';
    else
        std::cout << "weak1 is expired\n";

    // weak2 points to new data (5)
    if(auto tmp = weak2.lock())
        std::cout << *tmp << '\n';
    else
        std::cout << "weak2 is expired\n";
}

shared_ptr : contient l'objet réel.

weak_ptr : utilise le lock pour se connecter au propriétaire réel ou renvoie NULL dans le cas contraire.

Grosso modo, le rôle de weak_ptr est similaire au rôle de l' agence de logement . Sans agents, pour obtenir une maison en loyer, nous devrons peut-être vérifier les maisons au hasard dans la ville. Les agents veillent à ce que nous ne visitons que les maisons qui sont encore accessibles et disponibles à la location.





weak-ptr