C++11-enable_shared_from_this类
c++11 中的 shared_from_this() 来源于 boost 中的
enable_shared_form_this 类和 shared_from_this()
函数,功能为返回一个当前类的 std::share_ptr,使用方法如下:
1 2 3 4 5 6 7 8
| #include<memory> class Test: public std::enable_shared_from_this<Test> { public: Test(); ~Test(); std::shared_ptr<Test> getSharedFromThis() { return shared_from_this(); } }
|
enable_shared_from_this
的由来
在智能指针的使用过程中,我们会遇到这样一种情况,我们在类的成员函数调用某一个函数,而该函数需要传递一个当前对象的智能指针作为参数时,我们需要能够在成员函数中获得自己的智能指针。
在多线程程序中也存在这样的应用,如果我们的线程函数是一个成员函数,可以把该对象的智能指针作为参数传递到线程函数中,这种做法是人为的增加了对象的引用计数,延长对象的生命周期,防止线程函数在执行的时候对象被释放而引发内存错误。总之就是我们在实际的编码中会存在各种各样的应用。
我们可能有两个疑惑:
把当前类对象作为参数传给其他函数时,为什么要传递 share_ptr
呢?直接传递 this 指针不可以吗?
一个裸指针传递给调用者,谁也不知道调用者会干什么?假如调用者 delete
了该对象,而 share_tr此时还指向该对象。
这样传递 share_ptr 可以吗?share_ptr<this>
?
这样会造成2个非共享的share_ptr指向一个对象,最后造成2次析构该对象。
我们不能人为地通过 this 来构造一个当前对象的 shared_ptr
指标,如下错误的做法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <memory> class TestClass;
void Test(std::shared_ptr<TestClass> tt) {
}
class TestClass { public: TestClass() {} ~TestClass() {} void TestPtr() { std::shared_ptr<TestClass> tt = std::shared_ptr<TestClass>(this); Test(tt); } };
int main(int argc, char** argv) { std::shared_ptr<TestClass> t(new TestClass()); t->TestPtr(); return 0; }
|
在 TestPtr() 函数中通过 this 构造出
shared_ptr,就相当于把自己的的控制权交给了这个临时变量 tt,一旦 tt
超出作用域就会释放,导致该对象也被释放。这是一个致命的错误。
为了解决这个问题,在 C++11 中提供了 enable_shared_from_this
这个模板类(boost 库很早就提供了这个模板类),自己的对象继承自
enable_shared_from_this 。enable_shared_from_this
提供了一个shared_from_this()
的方法返回自己的智能指针。与上面错误的例子区别在于,shared_from_this
会增加该对象的引用计数,而不是重新建立一个临时的 shared_ptr
来管理。看下面具体的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <memory> class TestClass;
void Test(std::shared_ptr<TestClass> tt) {
}
class TestClass : public std::enable_shared_from_this<TestClass> { public: TestClass() {} ~TestClass() {} void TestPtr() { std::shared_ptr<TestClass> tt = shared_from_this(); Test(tt); } };
int main(int argc, char** argv) { std::shared_ptr<TestClass> t(new TestClass()); t->TestPtr(); return 0; }
|
shared_from_this() 函数
shared_from_this
的出现确实能够解决我们编码中所遇到的问题,但是它的坑也是比较多的。我们先来看看
enable_shared_from_this 这个对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| template<class _Ty> class enable_shared_from_this { public: typedef _Ty _EStype;
shared_ptr<_Ty> shared_from_this() { return (shared_ptr<_Ty>(_Wptr)); }
shared_ptr<const _Ty> shared_from_this() const { return (shared_ptr<const _Ty>(_Wptr)); }
protected: enable_shared_from_this() { }
enable_shared_from_this(const enable_shared_from_this&) { }
enable_shared_from_this& operator=(const enable_shared_from_this&) { return (*this); }
~enable_shared_from_this() { }
private: template<class _Ty1, class _Ty2> friend void _Do_enable( _Ty1 *, enable_shared_from_this<_Ty2>*, _Ref_count_base *);
mutable weak_ptr<_Ty> _Wptr; };
template<class _Ty1, class _Ty2> inline void _Do_enable( _Ty1 *_Ptr, enable_shared_from_this<_Ty2> *_Es, _Ref_count_base *_Refptr) { _Es->_Wptr._Resetw(_Ptr, _Refptr); }
|
这是标准库的源码,我们看到在 enable_shared_from_this 内部储存了一个
weak_ptr。shared_from_this 函数就是通过这个 weak_ptr
得到了。但是另外一点,我们可以看到在enable_shared_from_this
的构造函数中并没有对这个 weak_ptr 进行初始化。
这就是为什么我们不能在构造函数调用 shared_from_this()
的原因,因为其内部的 weak_ptr 并没有初始化。所以会产生错误。
在实际的程序设计中如果我们需要在对象初始化中用到自己的
shared_ptr。可以单独将初始化操作放到一个独立的 init 函数中,这时候再调用
shared_from_this() 是没有问题的(但还是有点问题,下面会讲到)
熟悉 weak_ptr 的同学可能知道,我们在使用 weak_ptr 前,需要用一个
shared_ptr 来对其进行初始化。对 weak_ptr
初始化是要能获取到当前对象的引用计数对象,而引用计数对象可以通过
shared_ptr 对象获取到。当然我们同样可以用一个已经初始化过的 weak_ptr
来初始化另一个 weak_ptr,因为已初始化的weak_ptr
也可能获取到对象的引用计数。
enable_shared_from_this 内部的 weak_ptr
是通过_Do_enable
函数初始化的。而_Do_enable
函数实在shared_ptr
的构造函数中调用的,这是至关重要的一个环节。正因为如此我们在调用
shared_from_this 之前请确保程序已经显式地建立了 shared_ptr
对象,要不然enable_shared_from_this 内部的 weak_ptr 始终是无效。
下面具体举例说明的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class TestClass : public std::enable_shared_from_this<TestClass> { public: TestClass() { } ~TestClass() { } void TestPtr() { std::shared_ptr<TestClass> tt = shared_from_this(); Test(tt); } };
int main() { TestClass t; t.TestPtr();
TestClass* t1(new TestClass()); t1->TestPtr();
std::shared_ptr<TestClass> t2(new TestClass()); t2->TestPtr(); }
|
同理在析构函数中也不能调用 shared_from_this()。
在析构时,引用计数已经变为零,weak_ptr
已经相当于指向的是一个无效的对象,不能通过此无效的 weak_ptr 构造
shared_ptr。
转载自C++11的enable_shared_from_this