弱引用指针weak_ptr是用来监视shared_ptr的,不会使引用计数器加1,它不管理shared_ptr内部的指针,主要是为了监视shared_ptr的生命周期,更像是shared_ptr的一个助手。weak_ptr没有重载操作符*和->,因为它不共享指针,不能操作资源,主要是为了通过shared_ptr获得资源的监测权,它的构造函数不会增加引用计数,它的析构不会减少引用计数,纯粹只是作为一个旁观者来监视shared_ptr中管理的资源是否存在。weak_ptr还可以用来返回this指针和解决循环引用的问题。
1、通过use_count()方法来获得当前观测资源的引用计数,代码如下:
- #include
- #include
- using namespace std;
-
- int main()
- {
- shared_ptr<int> sp(new int(1));
-
- weak_ptr<int> wp(sp);
-
- ///输出1
- cout << sp.use_count() << endl;
-
- ///输出1
- cout << wp.use_count() << endl;
-
- shared_ptr<int> sp2(new int(2));
-
- sp2 = sp;
-
- ///输出2
- cout << sp.use_count() << endl;
-
- return 0;
- }
-
2、通过expired()方法来判断所检测的资源是否已经被释放,代码如下:
- #include
- #include
- using namespace std;
-
- int main()
- {
- shared_ptr<int> sp(new int(1));
-
- weak_ptr<int> wp(sp);
-
- if (wp.expired())
- {
- cout << "weak_ptr无效,所监视的智能指针被释放" << endl;
- }
- else
- {
- cout << "weak_ptr 有效" << endl;
- }
-
- return 0;
- }
-
3、通过lock方法来获取所监视的shared_ptr,代码如下:
-
- #include
- #include
- using namespace std;
-
- std::weak_ptr<int> gw;
-
- void f()
- {
- if (gw.expired()) ///所监听的shared_ptr是否被释放
- {
- cout << "gw is exipired" << endl;
- }
- else
- {
- auto spt = gw.lock();
- cout << *spt << endl;
- }
- }
-
- int main()
- {
- {
- shared_ptr<int> sp(new int(1));
- gw = sp;
- f();
- }
-
- f();
-
- return 0;
- }
-
输出如下:
- 1
- gw is expired
不能直接将this指针返回为shared_ptr,需要通过派生std::enable_shared_from_this类,并通过其方法shared_from_this来返回智能指针,原因是std::enable_shared_from_this类中有一个weak_ptr,这个weak_ptr用来观测this指针,调用shared_from_this()方法时,会调用内部这个weak_ptr的lock()方法,将所观测的shared_ptr返回,看下面代码:
- #include
- #include
- #include
- #include
- using namespace std;
-
- {
- shared_ptr GetSelf()
- {
- return shared_from_this();
- }
-
- ///析构函数调用了1次
- ~A()
- {
- cout << "delete A" << endl;
- }
- };
-
- int main()
- {
- shared_ptr sp1(new A);
- shared_ptr sp2 = sp1->GetSelf();
-
- return 0;
- }
输出结果如下:
deleted A
在外面创建A对象的智能指针和通过该对象返回this的智能指针都是安全的,因此shared_from_this是内部的weak_ptr调用lock()方法之后返回的智能指针,在离开作用域之后,sp1的引用计数减为0,A对象会被析构,不会出现A对象被析构两次的问题。
智能指针的循环引用会导致内存泄漏问题,请看下面的代码:
- #include
- #include
- #include
- #include
- using namespace std;
-
- struct A;
- struct B;
-
- struct A
- {
- std::shared_ptr bptr;
- ~A()
- {
- cout << "A is deleted" << endl;
- }
- };
-
- struct B
- {
- std::shared_ptr aptr;
- ~B()
- {
- cout << "B is deleted" << endl;
- }
- };
-
-
- int main()
- {
- {
- ///析构函数没有被调用
- shared_ptr ap(new A);
- shared_ptr bp(new B);
- ap->bptr = bp;
- bp->aptr = ap;
-
-
- ///引用计数为2
- cout << "ap use_count: " << ap.use_count() << endl;
- cout << "bp use_count: " << bp.use_count() << endl;
- }
-
- return 0;
- }
在这个例子中,由于循环引用导致ap和bp的引用计数都为2,离开作用域之后引用计数减为1,不会去删除指针,导致内存泄漏。通过weak_ptr就可以解决这个问题,只要将A或者B的任意一个成员变量改为weak_ptr即可。
- struct A;
- struct B;
-
- struct A
- {
- std::shared_ptr bptr;
- ~A()
- {
- cout << "A is deleted" << endl;
- }
- };
-
- struct B
- {
- std::weak_ptr aptr;
- ~B()
- {
- cout << "B is deleted" << endl;
- }
- };
-
-
- int main()
- {
- {
- shared_ptr ap(new A);
- shared_ptr bp(new B);
- ap->bptr = bp;
- bp->aptr = ap;
-
- ///引用计数为1
- cout << "ap use_count: " << ap.use_count() << endl;
- cout << "bp use_count: " << bp.use_count() << endl;
- }
-
- return 0;
- }
-
输出如下:
- ap use_count: 1
- bp use_count: 2
- A is deleted
- B is deleted
这样在对B的成员赋值时,即执行bp->aptr = ap;时,由于aptr是weak_ptr,它并不会增加引用计数,所以ap的引用计数仍然会是1,在离开作用域之后,ap的引用计数会减少为0,A指针会被析构,析构后其内部的ptr的引用计数为减为1,然后再离开作用域后bp引用计数又从1减到0,B对象也会被析构,不会发生内存泄漏。