当你想使用一个类的某个成员函数返回指向这个类的指针的时候,可以这样写
class A
{
public:
A(int y=0):x(y){ }
A* getthis()
{
return this;
}
int x;
};
int main (void)
{
A a;
cout<<a.x<<endl;
A*p=a.getthis();
p->x=1;
cout<<a.x<<endl;
}
通过在成员函数中返回this指针,我们得到了指向这个对象本身的指针,并且可以通过它来改变对象。
但是在很多情况中,我们更想用智能指针去控制对象的生存周期,比如这样。
int main (void)
{
shared_ptr<A>sp1(new A());
shared_ptr<A>sp2(sp1->getthis());
cout<<sp1.use_count()<<endl;
cout<<sp2.use_count()<<endl;
}
两个智能指针的引用计数都是1,可想而知在函数退出的时候会发生什么,同一块内存被释放了两次,程序崩溃是免不了的。原因是this是裸指针,我们这么操作和用同一个裸指针给两个智能指针赋值是一个意思。如果我们能返回一个智能指针,那么问题就解决了。这时我们可以使用shared_from_this这个模版类。
class A:public enable_shared_from_this<A>
{
public:
A(int y=0):x(y){ }
shared_ptr<A> getthis()
{
return shared_from_this();
}
int x;
};
这样上面那段程序的输出是两个2,两个智能指针都意识到自己指向的是同一片内存,引用计数正确的发挥作用,同一片内存只会被析构一次。
除此之外,shared_from_this还有一个需要注意的地方。你可以点开shared_from_this的源码看看,他返回了enable_shared_from_this中唯一的一个成员变量
mutable weak_ptr<_Ty> _Wptr;
而当我们再看这个类的构造函数,并没有对这个成员变量赋值。可想而知,如果这个变量始终没有被赋值,那么我们无法使用shared_from_this这个函数。
为了弄清楚这个变量什么时候被赋值,我一步一步的调试了下面这行代码,虽说只有一行,但是他真的做了很多事情。
shared_ptr<A>sp1(new A());
来看这条语句,它做了三件事情,第一件事情是构造enable_shared_from_this这个类,毕竟想要构造A就要先构造他的父类。
此时wptr没有被赋值。
第二件事情是构造A,此时wptr也没有被赋值。
第三件事情,构造sp1,令人想不到的是,构造sp1之后,属于类A的父类的wptr被赋值了,整个过程跳来跳去说实话我也没看懂,反正是构造sp1之后,wptr才有了值。
所以可想而知,如果没有这样一个sp1的出现,我们是无法使用shared_from_this的。所以才有了所说的“不能再构造函数中调用shared_from_this()”的说法,这个构造函数指的是A的构造函数,因为那个时候wptr还没有值,当然不能调用shared_from_this。
当然了,这样也是不行的。
int main (void)
{
A a;
shared_ptr<A>sp(a.shared_from_this());
}
另外,在同一个继承体系中,不能同时出现多个enable_shared_from_this类。父类继承了enable之后,子类只能对shared_from_this()的返回值进行转型。也就是说把shared_ptr<A>转换成shared_ptr<B>,想做到这一点,你只能这么写
return dynamic_pointer_cast<B>(shared_from_this());