weak_ptr是为了解决shared_ptr的自引用以及交叉引用而引入的智能指针。顾名思义,weak_ptr是弱指针,因为其不具备指针的一系列操作:operator *,operator->,operator[]等,也不管理具体的原始指针。它仅仅作为一个观察者,协助shared_ptr管理原始指针。它既不使引用计数增减也不拥有原始指针,而且weak_ptr不可以直接使用原始指针进行构造,只能使用shared_ptr或另外一个weak_ptr来构造。虽然weak_ptr不管理原始指针,但是可以使用lock操作来返回一个shared_ptr。weak_ptr实现了拷贝构造函数和重载了赋值操作符,因此weak_ptr可以被用于标准容器库中的元素,例如:在一个树节点中声明子树节点std::vector<boost::weak_ptr<Node> >children。作为观察者,weak_ptr主要的操作有以下几种:
shared_ptr<T> lock() const;
long use_count() const;
bool expired() cosnt;//判断指针是否失效void reset();
void swap(weak_ptr<T> &b);
weak_ptr在自引用中的使用
weak_ptr很重要的一个作用是获取this指针的shared_ptr,使对象自己能够缠身管理自己的shared_ptr:对象使用weak_ptr观测this指针,并不影响引用计数,在需要的时候就调用lock函数,返回一个符合要求的shared_ptr供外界使用。这个方法被实现为一个模板类:
class enable_shared_from_this{public: shared_ptr shared_from_this();//工厂函数,产生this的shared_ptr};
使用shared_ptr管理this,必须使被管理的类public继承自enable_shared_from_this。以下为boost程序库完全开发指南第三版(page85 3.63)中的例子:
#include <iostream>
#include <memory>
using namespace std;
class self_shared:public enable_shared_from_this<self_shared>
{
public: self_shared(int n):x(n){}
void print() { cout << "self_shared x:" << x << endl; }
int x;
};
int main()
{
shared_ptr<self_shared> sp = make_shared<self_shared>(335);
sp->print();
auto p = sp->shared_from_this();
p->x = 100;
p->print();
getchar();
return 0;
}
weak_ptr在交叉引用中的使用 先看一个《C++标准库——第二版》中交叉引用的例子:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;
#define OUT_PTR_USE_COUNT(variable) do{\
cout << #variable << ".use_count() = " << variable.use_count() << endl;\
}while(0);
class Person {
public:
string name;
shared_ptr<Person> mother;
shared_ptr<Person> father;
vector<shared_ptr<Person>> kids;
Person(const string& n,
shared_ptr<Person> m = nullptr,
shared_ptr<Person> f = nullptr)
: name(n), mother(m), father(f) {
}
~Person() {
cout << "delete " << name << endl;
}
};
shared_ptr<Person> initFamily(const string& name)
{
shared_ptr<Person> mom(new Person(name + "’s mom"));
OUT_PTR_USE_COUNT(mom); //cout:1
shared_ptr<Person> dad(new Person(name + "’s dad"));
shared_ptr<Person> kid(new Person(name, mom, dad));
OUT_PTR_USE_COUNT(mom); //cout:2
mom->kids.push_back(kid);
dad->kids.push_back(kid);
OUT_PTR_USE_COUNT(mom); //cout:2
return kid;
}
int main()
{
shared_ptr<Person> p = initFamily("nico");
cout << "- nico is shared " << p.use_count() << " times" << endl; //cout:3
return 0;
//Person was not deleted when process return
}
由于交叉引用,导致在工厂函数initFamily中,mom在生命周期结束时,其引用计数由2变为1,造成自身没有被析构,然后导致child一直被mom和dad所持有,在声明周期结束时也没有被析构。从运行结果来看,所有的交叉引用的person对象都没有被析构!运行结果如下:
若在交叉引用的类中使用weak_ptr代替shared_ptr所有的问题都将得到解决。