本文共 2153 字,大约阅读时间需要 7 分钟。
C++11中引入了三种智能指针,分别是shared_ptr、weak_ptr和unique_ptr
智能指针可以帮助我们管理动态分配的堆内存,减少内存泄漏的可能性
手动管理堆内存有引起内存泄漏的可能,比如这段代码try { int* p = new int; // Do something delete p;} catch(...) { // Catch exception}
如果在执行Do something的时候发生了异常,那么程序就会直接跳到catch语句捕获异常,delete p这句代码不会被执行,发生了内存泄漏
我们把上面的程序改成try { shared_ptr p(new int); // Do something} catch(...) { // Catch exception}
当执行Do something的时候发生了异常,那么try块中的栈对象都会被析构。因此代码中p的析构函数会被调用,引用计数从1变成0,通过new分配的堆内存被释放,这样就避免了内存泄漏的问题
虽然智能指针会减少内存泄漏的可能性,但是如果使用智能指针的方式不对,一样会造成内存泄漏。比较典型的情况是循环引用问题,比如这段代码
class B; // 前置声明class A {public: shared_ptr ptr;};class B {public: shared_ptr ptr;};int main(){ while(true) { shared_ptr pa(new A()); shared_ptr pb(new B()); pa -> ptr = pb; pb -> ptr = pa; } return 0;}
这个程序中智能指针的引用情况如下图
上图中,class A和class B的对象各自被两个智能指针管理,也就是pa和pb引用计数都为2,为什么是2?
因为shared_ptr是一组指针指向一个实例,所以有几个shared_ptr指向类A,则类A就有几次引用。,class B对象同理。
在这种情况下,在main函数中一个while循环结束的时候,pa和pb的析构函数被调用,但是class A对象和class B对象仍然被一个智能指针管理,pa和pb引用计数变成1,于是这两个对象的内存无法被释放,造成内存泄漏,如下图所示
避免shared_ptr内存泄漏的利器。👈
smart pointer 三兄弟性格各异。unque_ptr是独来独往,shared_ptr是左拥右抱,而weak_ptr生来就不是为了单打独斗,了解之后你会发现他总是和shared_ptr出双入对。
weak_ptr为什么存在?
特性:
不可使用* 和 ->访问对象
被赋值,不会引起shared_ptr内部计数器值变化(我猜是它严格上来说不具备指针的能力---访问对象)
所以,我们就可以用weak_ptr替代shared_ptr, 看👇例子。
#include#include using namespace std;class B;class A{public: A() { cout << "A's constructor ..." << endl; } ~A() { cout << "A's destructor ..." << endl; } std::weak_ptr weak_b;};class B{public: B() { cout << "B's constructor ..." << endl; } ~B() { cout << "B's destructor ..." << endl; } std::weak_ptr weak_a;};int main(){ std::shared_ptr aa = make_shared(); //aa->object A aa计数器 1 std::shared_ptr bb = make_shared(); //bb->object B bb计数器 1 aa->weak_b = bb; //计数器还是1哦 bb->weak_a = aa; //计数器还是1哦 return 0;}
object A & B都被成功析构(销毁)了。那么循环引用导致shared_ptr发生内存泄漏的问题迎刃而解!
原因是:weak_ptr不会增加shared_ptr的计数器,从而离开mian函数作用域时,shared_ptr aa & bb 计数器都 -1 ,成为0, 具备销毁条件,调用析构函数销毁自己和所指对象
至此,我们终于可以说weak_ptr具备避免内存泄漏的功能了!!!
转载地址:http://hhndz.baihongyu.com/