慎用weak_from_this
最近使用C++的智能指针的时候遇到了一个坑,在此记录一下。
shared_from_this用法
使用std::shared_ptr创建的对象,可以在对象内使用构造一个指向自身的shared_ptr。条件是:
- 类自身需要继承 std::enable_shared_from_this<T>
- 对象需要由shared_ptr管理,可以用std::make_shared直接创建,也可以通过shared_ptr的构造函数来创建。
满足以上两个条件,即可在类的非构造函数中使用 shared_from_this获得一个指向自身对象的共享指针。那么如果不满足以上条件会怎么样呢?
- 不满足条件1,编译直接报错。
- 不满足条件2,比如在一个普通的new出来的对象、或者栈上的对象内调用shared_from_this,会在运行时抛异常。
两种报错机制都可以让开发者在误用的时候较快的发现问题,所以用起来还是比较放心。
weak_from_this的坑
现实中,我们使用shared_from_this的时候,经常是为了得到一个weak_ptr,比如传递一个弱引用给到另外的线程,这样用来确保不会因为生命周期的问题导致空悬引用。而shared_ptr又没有一个方法用来产生一个weak_ptr,必须通过weak_ptr的构造函数来获得,算是有点麻烦。
因此在C++17中,enable_shared_from_this类新增了一个weak_from_this方法,可以一步获得一个弱引用。
但是在实际使用中,发现使用weak_from_this时,如果不满足条件2,即 在没有使用shared_ptr管理的对象中使用weak_from_this,不会有任何异常,仅仅是在lock()的时候永远只能得到一个空指针。
这就比较危险了,误用的时候一直到最终的使用阶段才能发现问题。所以建议大家慎用weak_from_this函数。
原理
其实也简单,enable_shared_from_this内部放置了一个weak_ptr成员,并且将shared_ptr设置为friend,而shared_ptr在初始化时即会判断(编译期判断):如果要构造的类是enable_shared_from_this的派生类,则去将其中的weak_ptr成员设置好。
|
|
shared_from_this将该成员传递给shared_ptr构造,如果为空其构造函数会直接抛异常,weak_from_this却是直接返回了该成员本身,因此无论如何都不会抛异常。
|
|
事实上这种做法我觉得是欠妥的,两个明显是对等的函数,行为却不一致。
总之后续在使用stl函数时,有条件的话还是要看一看源码。