C++ Compartir con propiedad temporal (std :: weak_ptr)


Ejemplo

Las instancias de std::weak_ptr pueden apuntar a objetos que son propiedad de instancias de std::shared_ptr y solo se convierten en propietarios temporales. Esto significa que los punteros débiles no alteran el recuento de referencias del objeto y, por lo tanto, no impiden la eliminación de un objeto si todos los punteros compartidos del objeto se reasignan o destruyen.


En el siguiente ejemplo, se utilizan instancias de std::weak_ptr para que la destrucción de un objeto de árbol no se inhiba:

#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();
}

A medida que los nodos secundarios se agregan a los secundarios del nodo raíz, su parent std::weak_ptr miembro se establece en el nodo raíz. El parent miembro se declara como un puntero débil en lugar de un puntero compartido, de manera que el recuento de referencia del nodo raíz no se incrementa. Cuando el nodo raíz se reinicia al final de main() , la raíz se destruye. Dado que el único resto de std::shared_ptr referencias a los nodos secundarios estaban contenidos en la colección de la raíz children , todos los nodos hijos son posteriormente destruidos también.

Debido a los detalles de la implementación del bloque de control, la memoria asignada shared_ptr puede no liberarse hasta que el shared_ptr referencia weak_ptr y el weak_ptr referencia weak_ptr lleguen a cero.

#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)
}

Dado que std::weak_ptr no mantiene vivo su objeto referenciado, no es posible el acceso directo de datos a través de std::weak_ptr . En su lugar, proporciona una función miembro lock() que intenta recuperar un std::shared_ptr para el objeto al que se hace referencia:

#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());
     }
}