與臨時所有權共享(stdweak ptr)

std::weak_ptr例項可以指向由 std::shared_ptr例項擁有的物件,而只是自己成為臨時所有者。這意味著弱指標不會改變物件的引用計數,因此如果重新分配或銷燬所有物件的共享指標,則不會阻止物件的刪除。

在下面的示例中,使用了 std::weak_ptr 的例項,以便不會禁止破壞樹物件:

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

當子節點被新增到根節點的子節點時,他們的 std::weak_ptr 成員 parent 被設定為根節點。成員 parent 被宣告為弱指標而不是共享指標,因此根節點的引用計數不會遞增。當根節點在 main() 結束時重置時,根被破壞。由於對子節點的唯一剩餘的 std::shared_ptr 引用包含在根的集合 children 中,所以所有子節點隨後也被銷燬。

由於控制塊實現細節,在 shared_ptr 參考計數器和 weak_ptr 參考計數器都達到零之前,可能不會釋放 shared_ptr 分配的記憶體。

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

由於 std::weak_ptr 不會使其引用的物件保持活動狀態,因此無法通過 std::weak_ptr 直接訪問資料。相反,它提供了一個 lock() 成員函式,它試圖將 std::shared_ptr 檢索到引用的物件:

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