與臨時所有權共享(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());
}
}