与临时所有权共享(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());
}
}