c++编程实践—为什么需要weak_ptr
一、智能指针
在C/C++的开发中,指针的开发一直是一个老大难的问题,也是所有开发者感觉容易出问题的一个技术点。在早期推出过各种版本的autoptr,用着感觉不爽。所以一直也没有在开发广泛流行起来。从C++11起,新标准推出了智能指针shared_ptr和weak_ptr。前者好理解,指针可以共享,通过计数器来处理指针到底还有没有使用。但后者就会让开发者有些疑问,为什么出一个weak_ptr?它有什么作用呢?在哪里适用它呢?
二、weak_ptr
std::weak_ptr,弱引用智能指针。如果有过Boost库相关的智能指针开发的可能非常好理解。区别于std::shared_ptr,这个指针在拿到后,需要做一个判断,确定真正的对象仍然存在,才可能使用。类似下面的代码:
std::weak_ptr<Demo>wPtr;{std::shared_ptr<Demo>sPtr=std::make_shared<Demo>();wPtr=sPtr;}if(std::make_shared<Demo>sp=wPtr.lock()){//yes}else{//no}这也意味着,weak_ptr其实无法直接访问对象,它不保证指针对象生命周期的存在即不影响生命周期,同样,它也不会影响shared_ptr的引用计数器。可以理解为,它只是一个智能指针的标记,标记后到底是否存在指针对象,它不做保证。
std::weak_ptr的主要作用在于解决智能指针的循环引用。也就是std::shared_ptr之间的互相引用,导致的资源泄露。除了这一种重要的情况外,它还可以实现对所有权的监视(不持有),这样既可以保证随时对指针对象的安全获取,但又不会增加智能指针的计数器,提高应用的安全性。
三、应用场景及分析
其实在弱引用智能指针的应用场景中,主要有以下几种情况:
- 破除std::shared_ptr循环引用
这是std::weak_ptr最典型的一种用法。资源永远是计算机世界中最重要的东西,所以不可能平白的让资源白白消耗掉。实际场景中的代码如下:
//内存泄露的场景class Node{public:std::shared_ptr<Node>next;// std::shared_ptr<Node> prev; //导致循环引用std::weak_ptr<Node>prev;// weak_ptr打破循环引用};auton1=std::make_shared<Node>();auton2=std::make_shared<Node>();n1->next=n2;n2->prev=n1;前后两个node节点互相持有,导致资源如果不强行干涉的话,永远不会释放,这就会造成内存泄露。
- 所有权(生命周期)的监控
这也是weak_ptr一种比较常见的应用方式,比如在多线程、异步、库交互或事件通知等跨生命周期的活动中,既可能为了防止对象意外的释放,又有可能是减少对队列中生命周期控制的单一性,都可以使用weak_ptr(也可以理解为无法确定对象指针的生命周期的确定性时)。为了保证最终应用时,对象指针的安全就需要使用weak_ptr。看cppreference上的例子:
#include<iostream>#include<memory>std::weak_ptr<int>gw;voidobserve(){std::cout<<"gw.use_count() == "<<gw.use_count()<<"; ";// we have to make a copy of shared pointer before usage:if(std::shared_ptr<int>spt=gw.lock())std::cout<<"*spt == "<<*spt<<'\n';elsestd::cout<<"gw is expired\n";}intmain(){{autosp=std::make_shared<int>(42);gw=sp;observe();}observe();}- 设计策略
从设计上考虑,为了保证安全及统一管理。除本地使用shared_ptr外,其它提供给相关应用各方的都是weak_ptr。 - 接口提供了weak_ptr指针
这个没有办法,别人的库、框架或接口提供了这个指针,则只能使用weak_ptr
上面的几种应用场景,其实主要还是防止std::shared_ptr指针的互相持有导致的可能各种资源的泄露。基于设计上的安全的考虑的目的以及所有权的监视只不过是可能互相持有的一种外沿罢了。
四、总结
std::weak_ptr是用来解决问题的,这是它出现的目的。而出现问题与正常使用相比,总是一种小概率事件。这也意味着,开发者不要把std::weak_ptr当成一种广泛使用情况。它只适合于在上面提到的一些具体情况下才适用。即合适的技术要用在合适的场景下,否则非但不能解决问题,反而可能引入更多的问题。
