C++ 智能指针weak_ptr用途浅析
2020-01-15 00:48
120 查看
文章目录
C++ 智能指针weak_ptr用途浅析
我们知道C++智能指针有
shared_ptr和
unique_ptr,这两种指针基本就可以胜任堆内存的管理了,那么C++为什么还要提出
weak_ptr呢?
weak_ptr这个东西到底有什么用途呢?
1. weak_ptr的特性
weak_ptr也是指向
shared_ptr指向的对象,但是并不管理引用计数和内存,操作如下:
所以,如果要使用weak_ptr,必须锁定为shared_ptr
shared_ptr<element_type> lock() const noexcept;
从上面我们也可以知道,weak_ptr的初始化也是从shared_ptr来的,如下:
//default (1) constexpr weak_ptr() noexcept; //copy (2) weak_ptr (const weak_ptr& x) noexcept; template <class U> weak_ptr (const weak_ptr<U>& x) noexcept; //from shared_ptr (3) template <class U> weak_ptr (const shared_ptr<U>& x) noexcept;
从这里来看,
weak_ptr完全就是一个
shared_ptr鸡肋功能啊,一点用的没有。
真是这样的吗?我们看一下下面分析。
2. 二叉树的实现
2.1 问题
这里我们实现一个简单的二叉树,就三个节点,根,左子树,右子树(二叉树是一种非常查用的数据结构,这里使用这个例子,说明在我们实际情况中,这种场景其实非常多)。
struct Node { std::shared_ptr<Node> Parent; std::shared_ptr<Node> LeftChild; std::shared_ptr<Node> RightChild; int Data; // Node(int d) : Data(d) {} ~Node() { std::cout << "~Node() called" << std::endl; } }; void Tree() { std::shared_ptr<Node> Root = std::make_shared<Node>(200); std::shared_ptr<Node> Left = std::make_shared<Node>(100); std::shared_ptr<Node> Right = std::make_shared<Node>(300); Root->LeftChild = Left; Root->RightChild = Right; Left->Parent = Root; Right->Parent = Root; }
如果我们运行这段代码可以发现,没有任何输出,析构函数并没有被调用?内存就这样被泄露了?我们来分析一下这段代码:
std::shared_ptr<Node> Root = std::make_shared<Node>(200);
: Root的引用计数为1.std::shared_ptr<Node> Left = std::make_shared<Node>(100);
: Left引用计数为1.std::shared_ptr<Node> Right = std::make_shared<Node>(300);
: Right 引用计数为1.Root->LeftChild = Left;
: Left引用计数为2.Root->RightChild = Right;
: Right引用计数为2.Left->Parent = Root;
: Root引用计数为2.Right->Parent = Root;
: Root引用计数为3.
离开作用域的时候:
- Root被释放,引用计数减1 为2.
- Left被释放,引用计数为1.
- Right被释放,引用计数为1.
也就是说,所有的引用计数都不为0,没有任何对象被释放;这个也就是典型的环形引用;也就是说,shared_ptr在环形引用中会导致引用计数循环使用。
解决办法两种。
2.2 方案1
void Tree() { std::shared_ptr<Node> Root = std::make_shared<Node>(200); std::shared_ptr<Node> Left = std::make_shared<Node>(100); std::shared_ptr<Node> Right = std::make_shared<Node>(300); Root->LeftChild = Left; Root->RightChild = Right; Left->Parent = Root; Right->Parent = Root; Root->LeftChild.reset(); Root->RightChild.reset(); Left->Parent.reset(); Right->Parent.reset(); }
此时执行结果:
~Node() called ~Node() called ~Node() called
这种办法很明确,Root快要释放的时候,左右的清理,同样左右子树也一样,不过这种方法也太扯淡了,下面提供另外一种办法。
2.3 方案2
我们可以这么理解,对于一个节点来说,只要不是根,那么父节点应该是存在的,子节点就不一定,所以我们可以将子节点声明为弱引用:
struct Node { std::shared_ptr<Node> Parent; std::weak_ptr<Node> LeftChild; std::weak_ptr<Node> RightChild; int Data; // Node(int d) : Data(d) {} ~Node() { std::cout << "~Node() called" << std::endl; } }; void Tree() { std::shared_ptr<Node> Root = std::make_shared<Node>(200); std::shared_ptr<Node> Left = std::make_shared<Node>(100); std::shared_ptr<Node> Right = std::make_shared<Node>(300); Root->LeftChild = Left; Root->RightChild = Right; Left->Parent = Root; Right->Parent = Root; }
此时执行结果:
~Node() called ~Node() called ~Node() called
至于引用计数,大家可以自己算一算。当然这里,也可以直接将parent作为弱引用,理解不同随意设置都可以。
3. 总结
当然上面树的例子只是一个说明,真实场景可能有很多会有类型情况。总之
shared_ptr在环形引用中,带来了循环引用的弊端,所以,需要将其中一个设置为弱引用(根据实际情况确定,一般将管理者使用
shared_ptr,其他引用管理者的使用
weak_ptr,这么看刚刚的树的
weak_ptr属性刚好设置反了)。
因为循环引用,析构的时候只能释放一次引用计数;而实际的引用计数为2.
- 点赞 5
- 收藏
- 分享
- 文章举报
相关文章推荐
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- C++智能指针:TR1的 shared_ptr 和 weak_ptr 使用介绍
- C++智能指针 shared_ptr 与 weak_ptr 原理
- 从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
- 智能指针weak_ptr用途
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- [置顶] 从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
- C++智能指针--weak_ptr
- 深入学习c++--智能指针(二) weak_ptr (打破shared_ptr循环引用)
- C++ 智能指针(shared_ptr/weak_ptr)源码分析
- C++ 智能指针shared-ptr,unique_ptr和weak-ptr
- C++智能指针:auto_ptr、shared_ptr、weak_ptr等
- c++智能指针(五)之weak_ptr
- C++ 智能指针 shared_ptr unique_ptr weak_ptr
- C++智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> )
- c++ 智能指针之weak_ptr
- C++学习之智能指针--auto_ptr、scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr
- 详解C++各种智能指针: auto_ptr, shared_ptr, weak_ptr, scoped_ptr
- c++中的smart pointer四个智能指针: shared_ptr,unique_ptr,weak_ptr,auto_ptr
- [置顶] 从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)