介绍
weak_ptr
这个指针天生一副“小弟”的模样,也是在C++11的时候引入的标准库,它的出现完全是为了弥补它老大shared_ptr
天生有缺陷的问题,其实相比于上一代的智能指针auto_ptr
来说,新进老大shared_ptr
可以说近乎完美,但是通过引用计数实现的它,虽然解决了指针独占的问题,但也引来了引用成环的问题,这种问题靠它自己是没办法解决的,所以在C++11的时候将shared_ptr
和weak_ptr
一起引入了标准库,用来解决循环引用的问题。
weak_ptr
本身也是一个模板类,但是不能直接用它来定义一个智能指针的对象,只能配合shared_ptr
来使用,可以将shared_ptr
的对象赋值给weak_ptr
,并且这样并不会改变引用计数的值。查看weak_ptr
的代码时发现,它主要有lock
、swap
、reset
、expired
、operator=
、use_count
几个函数,与shared_ptr
相比多了lock
、expired
函数,但是却少了get
函数,甚至连operator*
和 operator->
都没有,可用的函数数量少的可怜,下面通过一些例子来了解一下weak_ptr
的具体用法。
代码验证如下:
#include <iostream>
#include <memory> //auto_ptr 的头文件
#include <string>
using namespace std;
class ptrTest
{
public:
ptrTest(int i) {
index = i;
cout << "ptrTest():"<<i<<endl;
};
~ptrTest() {
cout << "delete ptrTest:" << index << endl;
};
public:
int getIndex() {
return index;
};
private:
int index = 0;
};
void main() {
{
shared_ptr<ptrTest> ptr_a(new ptrTest(1));
shared_ptr<ptrTest> ptr_b(new ptrTest(2));
cout << "ptr_a use_count:" << ptr_a.use_count()<<endl;
cout << "ptr_b use_count:" << ptr_b.use_count() << endl;
weak_ptr<ptrTest> wptr_a = ptr_a;
shared_ptr<ptrTest> ptr_c = ptr_b;
cout << "wptr_a use_count:" << ptr_a.use_count() << endl;
cout << "ptr_c use_count:" << ptr_b.use_count() << endl;
}
system("pause");
}
运行结果:
weak_ptr智能指针使用如下:
#include <iostream>
#include <memory> //auto_ptr 的头文件
#include <string>
using namespace std;
class ptrTest
{
public:
ptrTest(int i) {
index = i;
cout << "ptrTest():"<<i<<endl;
};
~ptrTest() {
cout << "delete ptrTest:" << index << endl;
};
public:
int getIndex() {
return index;
};
private:
int index = 0;
};
void main() {
{
//
shared_ptr<ptrTest> ptr_a(new ptrTest(1));
shared_ptr<ptrTest> ptr_b(new ptrTest(2));
cout << "ptr_a use_count:" << ptr_a.use_count() << endl;
cout << "ptr_b use_count:" << ptr_b.use_count() << endl;
weak_ptr<ptrTest> wptr_a = ptr_a;
shared_ptr<ptrTest> ptr_c = ptr_b;
cout << "wptr_a use_count:" << ptr_a.use_count() << endl;
cout << "ptr_c use_count:" << ptr_b.use_count() << endl;
if (!wptr_a.expired())
{
shared_ptr<ptrTest> ptr_d = wptr_a.lock();
cout << "wptr_a lock use_count:" << wptr_a.use_count() << endl;
}
}
system("pause");
}
运行结果:
循环引用
weak_ptr可以解决shared_ptr循环引用问题,导致内存泄漏问题,问题模型如下图:
当shared_ptr类型的spA、spB对象析构时,ref_count 减一;由于Obj A 和 Obj B中的shared_ptr智能指针还相互引用,导致ref_count不为零,spA和spB不会去析构所指的对象,最终导致内存泄漏。
当Obj A 和 Obj B中的智能指针是weak_ptr是,不会影响share_ptr智能指针引用计数,当spA和spB析构时,导致ref_count为零,同时所指向的对象也就被析构了;其解决方案模型如下:
代码实例如下:
//strong reference
class B;
class A
{
public:
shared_ptr<class B> m_spB;
};
class B
{
public:
shared_ptr<class A> m_spA;
};
//weak reference
class WeakB;
class WeakA
{
public:
weak_ptr<class WeakB> m_wpB;
};
class WeakB
{
public:
weak_ptr<class WeakA> m_wpA;
};
void test_loop_ref()
{
weak_ptr<class A> wp1;
{
auto pA = make_shared<class A>();
auto pB = make_shared<class B>();
pA->m_spB = pB;
pB->m_spA = pA;
wp1 = pA;
}//内存泄漏
cout << "wp1 reference number: " << wp1.use_count() << "\n";
weak_ptr<class WeakA> wp2;
{
auto pA = make_shared<class WeakA>();
auto pB = make_shared<class WeakB>();
pA->m_wpB = pB;
pB->m_wpA = pA;
wp2 = pA;
}//无内存泄漏
cout << "wp2 reference number: " << wp2.use_count() << "\n";
}
int main()
{
//std::weak_ptr 用来避免 std::shared_ptr 的循环引用
test_loop_ref();
return 0;
}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
wp1和wp2作为shared_ptr智能指针的核查器,其检测结果如下:
wp1 reference number: 1//内存泄漏
wp2 reference number: 0//问题解决