1.为什么需要enable_shared_from_this
enable_shared_from_this是为了解决调用shared_ptr构造函数时无法通过原指针(被管理的对象)增加共享指针的统一引用计数(两个非共享的shared_ptr指向同一个对象,未增加引用计数导对象被析构两次)。至于它的具体实现后文再说。
有如下一个资源类
class Obj {
int id_;
public:
Obj(int id):id_(id) {
cout << "创建了一个Obj对象:"<<id_<<endl;
}
~Obj() {
cout << "析构了Obj对象:"<<id_<<endl;
}
shared_ptr<Obj> getPtr() {
shared_ptr<Obj> res = std::move(shared_ptr<Obj>(this));
cout <<"getPtr中shared_ptr的引用计数:"<< res.use_count() << endl;
return res;
}
};
我们用shared_ptr管理它生成的对象,这个资源类的成员函数getPtr的作用是返回当前对象的shared_ptr。然后我们执行下面的测试程序。
void test_shared_from_this() {
cout << "1..............." << endl;
shared_ptr<Obj> obj1(new Obj(1));
cout << "2..............." << endl;
shared_ptr<Obj> obj2 = obj1->getPtr();
cout << "3..............." << endl;
cout << "obj1的引用计数个数:"<< obj1.use_count() << endl;
cout << "obj2的引用计数个数:"<< obj2.use_count() << endl;
}
得到的结果为:
1...............
创建了一个Obj对象:1
2...............
getPtr中shared_ptr的引用计数:1
3...............
obj1的引用计数个数:1
obj2的引用计数个数:1
析构了Obj对象:1
析构了Obj对象:-572662307
注:在vs2017中是触发了一个异常断点,实际上是重复释放了内存。
从结果可知,创建了一个对象,却析构了两次。为什么会这样?
通过shared_ptr<Obj> obj1(new Obj(1));
创建了一个id=1的Obj对象,并用智能指针obj1管理它(通过智能指针的构造函数实现),此时obj1中的引用计数为1;然后想通过该对象的getPtr成员函数返回一个智能指针赋值给obj2,在shared_ptr<Obj> res = std::move(shared_ptr<Obj>(this));
中,我们还是通过构造函数的方式来产生智能指针,因为智能指针的构造函数是不共享引用计数的,所以此时obj2中的引用计数还是1,但是obj1和obj2管理的确是同一个Obj对象,这就导致在函数退出时,该Obj对象被析构了两次。如果将shared_ptr<Obj> obj2 = obj1->getPtr();
改为调用拷贝构造函数,也即shared_ptr<Obj> obj2(obj1);
,则有
1...............
创建了一个Obj对象:1
2...............
3...............
obj1的引用计数个数:2
obj2的引用计数个数:2
析构了Obj对象:1
此时虽然正确了,但是没有实现要求的getPtr的功能。此时就需要enable_shared_from_this了。
通过继承enable_shared_from_this后,调用该模板类的成员函数share_from_this,就可以实现getPtr的功能。此时代码为
class Obj:public enable_shared_from_this<Obj> {
int id_;
public:
Obj(int id):id_(id) {
cout << "创建了一个Obj对象:"<<id_<<endl;
}
~Obj() {
cout << "析构了Obj对象:"<<id_<<endl;
}
shared_ptr<Obj> getPtr() {
/*shared_ptr<Obj> res = std::move(shared_ptr<Obj>(this));
cout <<"getPtr中shared_ptr的引用计数:"<< res.use_count() << endl;
return res;*/
return shared_from_this();
}
};
结果为:
1...............
创建了一个Obj对象:1
2...............
3...............
obj1的引用计数个数:2
obj2的引用计数个数:2
析构了Obj对象:1
2.enable_shared_from_this模板类的实现
enable_shared_from_this中包含一个mutable weak_ptr<T> Wptr_;
成员变量,继承enable_shared_from_this也就继承了该变量,当第一次构造智能指针时shared_ptr<Obj> obj1(new Obj(1));
就会初始化Wptr_来指向new出来的对象。再通过share_from_this()代替shared_ptr的普通构造函数返回一个shared_ptr对象,避免产生额外的引用计数器,share_from_this就是通过t提升Wptr_来返回一个shared_ptr。