概述
在C++11 标准中,智能指针的引入极大地提升了内存管理的安全性和便利性。除了已经广为人知的shared_ptr和unique_ptr之外,还有一个重要但相对较少被单独提及的智能指针类型——std::weak_ptr。std::weak_ptr是C++ 11引入的一种弱引用智能指针,它不拥有所指向对象的所有权,而是对shared_ptr持有的对象提供一种非拥有但可观察的访问方式。weak_ptr主要用于打破共享所有权循环引用的问题,防止出现内存泄漏。
工作原理
1、不增加引用计数。
当创建一个weak_ptr时,它不会增加其所指向的对象的引用计数。这意味着,即使有多个weak_ptr指向同一对象,只要没有对应的shared_ptr存在,该对象仍会在所有shared_ptr释放后被正确销毁。
2、检查有效性。
通过调用weak_ptr的lock()成员函数,可以获取一个指向同一对象的shared_ptr。如果此时对象已被删除,则返回的shared_ptr为空。因此,在使用weak_ptr之前通常需要先调用lock()来检查对象是否仍然有效。
3、不阻止对象析构。
由于weak_ptr仅提供了对目标对象的弱引用,所以在没有活跃的shared_ptr指向该对象时,对象会被正常回收。
使用案例
单纯使用shared_ptr有时会产生问题,考虑下面的示例代码。
#include <iostream> using namespace std; class A; class B; typedef shared_ptr<A> A_Share; typedef shared_ptr<B> B_Share; class A { public: B_Share m_b; }; class B { public: A_Share m_a; }; int main() { A_Share a(new A()); B_Share b(new B()); a->m_b = b; b->m_a = a; return 0; }
在上面的示例代码中,a和b相互进行引用。在a和b离开作用域时,a和b的引用计数都是1,内存没有正常释放。解决方法是:将A和B中的任意一个类声明的变量改为week_ptr类型。比如:修改类B后的参考代码如下。
class B { public: weak_ptr<A> m_a; };
修改后,b.m_a = a不会增加A对象的引用计数。因此,a离开作用域时,引用计数为0。B对象的引用计数为2,在a和b离开作用域时,引用计数各减1后也为0,从而被正常释放。
应用场景
1、打破循环引用。
在两个或多个具有相互引用关系的对象之间使用shared_ptr时,如果没有弱引用的存在,可能会形成循环引用,导致即使外部不再有任何其他引用,这些对象也无法被垃圾回收。在这种情况下,可以通过将一部分引用改为weak_ptr来解决此问题。
2、缓存与观察者模式。
在设计缓存系统或者观察者模式时,某个对象可能需要知道另一个对象的状态变化,但并不希望影响该对象的生命周期。这时,可以使用weak_ptr来跟踪对象,而不增加其引用计数。
总结
std::weak_ptr作为C++ 11的新特性之一,为了解决循环引用和实现特定设计模式提供了关键工具。理解和熟练运用weak_ptr,有助于编写更加安全且资源高效的C++程序。同时,应当注意在恰当的场景下结合shared_ptr一起使用,以达到最佳效果。