weak_ptr 可以用来干嘛
智能指针中,除了大家喜闻乐见的shared_ptr,还有一个奇葩的weak_ptr。我读到这里时,就想,这货有什么用呢,获得对象又不增加引用计数?老老实实用着shared_ptr不是挺好的?标准库里何必要搞出这样的一个东西来?
毫无疑问我错了。weak_ptr有着极为重要的作用……
从实际问题谈起
在大作业中,我遇到了这样的需求:在一个对象的成员函数内,将这个对象的shared_ptr作为参数传入另一个函数中。值得注意的是,这个对象设计为只应通过shared_ptr调用。当然这个需求不是必要的,只是为了封装的完整、易用。
在成员函数中,我只能通过this获得这个对象的普通指针,而不能直接获得它的智能指针。那么我该怎么办呢?
- 用普通指针构造一个
shared_ptr?
如此一来,虽得到了一个指向对象的智能指针,但这不是我想要的智能指针——它与原有的智能指针有着完全不同的引用计数。当其中一个智能指针析构之后,另一个指针很有可能还会存在,并继续调用这个对象——显然,这会导致异常出现。这就是为什么 «C++ Primer» 会苦口婆心地告诫我们:不要混用普通指针和智能指针。
- 把
shared_ptr作为成员变量储存?
很好,现在解决了两个shared_ptr不同的问题,使用过程中也不会出现异常了。然而,新的问题又出现了:由于这个对象永远保有它自己的shared_ptr,其引用计数永远不会归零,它永远不会被析构掉,它会一直存在于内存中,就如同全局变量一般。这显然不是我们希望看到的。
- 那该怎么办呢?
聪明的你一定想到了,既然我们谈的是weak_ptr的作用,那一定是用weak_ptr来解决这个问题咯。没错,通过储存这个成员的weak_ptr,我们就能很开心地随时得到这个对象的shared_ptr了。
改进
前面提到,这个对象具有一个特点:这个对象设计为只能通过shared_ptr调用。因而,为了避免勿用普通指针,造成普通指针和智能指针混用的情况,我们最好对其进行封装。首先,普通的构造函数对这个类肯定是不适用,它不能满足产生智能指针的效果。其次,应当给成员变量初始化weak_ptr。最后,应当防范取地址符获取到普通指针的情况。
代码实现
class Foo{
public:
static std::shared_ptr<Foo> new_foo(int i);
std::shared_ptr<Foo> operator&();
~Foo();
private:
Foo(int i);
void init_weak_pointer();
int x;
std::weak_ptr<Foo> thisWeakPointer;
};
std::shared_ptr<Foo> Foo::new_foo(int i){
std::shared_ptr<Foo> sharedPointer(new Foo(i));
sharedPointer->init_weak_pointer(sharedPointer);
return sharedPointer;
}
std::shared_ptr<Foo> operator&(){
std::shared_ptr<Foo> sharedPointer = thisWeakPointer.lock();
try{
if(sharedPointer){
return sharedPointer;
}
else{
throw std::logic_error("Foo class can only be used with shared_ptr!");
}
}
}
Foo::~Foo(){}
Foo::Foo(int i): x(i){}
void Foo::init_weak_pointer(std::shared_ptr<Foo> sharedPointer){
thisWeakPointer = sharedPointer;
}