C++ Condivisione con proprietà temporanea (std :: weak_ptr)


Esempio

Le istanze di std::weak_ptr possono puntare a oggetti di proprietà di istanze di std::shared_ptr mentre diventano essi stessi solo proprietari temporanei. Ciò significa che i puntatori deboli non alterano il conteggio dei riferimenti dell'oggetto e quindi non impediscono la cancellazione di un oggetto se tutti i puntatori condivisi dell'oggetto sono riassegnati o distrutti.


Nel seguente esempio vengono utilizzate istanze di std::weak_ptr modo che la distruzione di un oggetto ad albero non sia inibita:

#include <memory>
#include <vector>

struct TreeNode {
    std::weak_ptr<TreeNode> parent;
    std::vector< std::shared_ptr<TreeNode> > children;
};

int main() {
    // Create a TreeNode to serve as the root/parent.
    std::shared_ptr<TreeNode> root(new TreeNode);

    // Give the parent 100 child nodes.
    for (size_t i = 0; i < 100; ++i) {
        std::shared_ptr<TreeNode> child(new TreeNode);
        root->children.push_back(child);
        child->parent = root;
    }

    // Reset the root shared pointer, destroying the root object, and
    // subsequently its child nodes.
    root.reset();
}

Quando i nodi figli vengono aggiunti ai figli del nodo radice, il loro parent membro std::weak_ptr viene impostato sul nodo radice. Il membro parent viene dichiarato come un puntatore debole anziché un puntatore condiviso, in modo che il conteggio dei riferimenti del nodo radice non venga incrementato. Quando il nodo root viene ripristinato alla fine di main() , la root viene distrutta. Dal momento che i restanti solo std::shared_ptr riferimenti ai nodi secondari erano contenuti nella collezione del radice children , tutti i figli vengono successivamente distrutti pure.

A causa dei dettagli di implementazione del blocco di controllo, la memoria allocata shared_ptr potrebbe non essere rilasciata fino a shared_ptr contatore di riferimento weak_ptr e il weak_ptr riferimento weak_ptr entrambi raggiungono lo zero.

#include <memory>
int main()
{
    {
         std::weak_ptr<int> wk;
         {
             // std::make_shared is optimized by allocating only once 
             // while std::shared_ptr<int>(new int(42)) allocates twice.
             // Drawback of std::make_shared is that control block is tied to our integer
             std::shared_ptr<int> sh = std::make_shared<int>(42);
             wk = sh;
             // sh memory should be released at this point...
         }
         // ... but wk is still alive and needs access to control block
     }
     // now memory is released (sh and wk)
}

Poiché std::weak_ptr non mantiene std::weak_ptr suo oggetto di riferimento, l'accesso diretto ai dati tramite uno std::weak_ptr non è possibile. Fornisce invece una funzione membro lock() che tenta di recuperare un oggetto std::shared_ptr sull'oggetto di riferimento:

#include <cassert>
#include <memory>
int main()
{
    {
         std::weak_ptr<int> wk;
         std::shared_ptr<int> sp;
         {
             std::shared_ptr<int> sh = std::make_shared<int>(42);
             wk = sh;
             // calling lock will create a shared_ptr to the object referenced by wk
             sp = wk.lock();
             // sh will be destroyed after this point, but sp is still alive
         }
         // sp still keeps the data alive.
         // At this point we could even call lock() again 
         // to retrieve another shared_ptr to the same data from wk
         assert(*sp == 42);
         assert(!wk.expired());
         // resetting sp will delete the data,
         // as it is currently the last shared_ptr with ownership
         sp.reset();
         // attempting to lock wk now will return an empty shared_ptr,
         // as the data has already been deleted
         sp = wk.lock();
         assert(!sp);
         assert(wk.expired());
     }
}