直接引入了enable_shared_from_this, 懂得都懂, 不懂的去查,就不科普了
使用方式
class Observer : public enable_shared_from_this<Observer> {
private:
// 1. 避免产生非智能指针的对象, 这个是使用enable_shared_from_this 要注意的一点, 不然会产生 weak_ptr bad_alloc异常
Observer() {
cout << "Observer::Observer()" << endl;
}
public:
// 代替构造函数产生智能指针对象
static shared_ptr<Observer> getInstance() {
cout << "D::getInstance()" << endl;
shared_ptr<Observer> ob(new Observer);
return ob->shared_from_this();
}
};
int main() {
auto d = Observer::getInstance();
}
输出
原理剖析
疑问1、class Observer : public enable_shared_from_this<Observer> 这种继承怎么回事?
在语法上, 只要enable_shared_from_this内部不调用Observer成员对象以及方法的话那么在语法上是那没问题, 特别指出enable_shared_from_this可以拥有指向Observer的指针,这个enable_shared_from_this 确实是这么实现的, 它有一个 weak_ptr 指针, 如下
疑问 2、weak_ptr 这个指针什么时候赋值的
这个问题很有意思,它居然是在 shared_ptr的重载的某一个构造函数里面赋值的
这段代码解析,主要是 typename这段代码, 其实就是提供了一个默认参数并给了默认值, 只有满足这个构造函数的参数列表才会调用这个函数
template<class _Tp>
template<class _Yp>
shared_ptr<_Tp>::shared_ptr(_Yp* __p,
typename enable_if<is_convertible<_Yp*, enable_shared_from_this<_Yp>*>::value, __nat>::type)
: __ptr_(__p)
{
//unique_ptr<_Yp> __hold(__p);
//typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT;
//typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, _AllocT > _CntrlBlk;
//__cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), _AllocT());
//__hold.release();
__enable_weak_this(__p, __p);
}
template <class _Yp, class _OrigPtr>
typename enable_if<is_convertible<_OrigPtr*,
const enable_shared_from_this<_Yp>*
>::value,
void>::type
__enable_weak_this(const enable_shared_from_this<_Yp>* __e,
_OrigPtr* __ptr) _NOEXCEPT
{
typedef typename remove_cv<_Yp>::type _RawYp;
if (__e && __e->__weak_this_.expired())
{
__e->__weak_this_ = shared_ptr<_RawYp>(*this,
const_cast<_RawYp*>(static_cast<const _Yp*>(__ptr)));
}
}
_LIBCPP_INLINE_VISIBILITY void __enable_weak_this(...) _NOEXCEPT {}
可以看到结果一目了然, 关于这里面貌似很复杂的 typename enable_if 这种的原理, 有机会给大家讲将。
shared_from_this()的原理
多么简单!
后记
从__enable_weak_this 我们知道如果最开始的本身对象不是指针那么最终 weak_ptr 将不会得到复制这时候,shared_from_this()放回的就是一个空指针
所以我为什么会不放开构造函数权限,而使用getInstance来避免问题
更复杂的代码可以看看
https://blog.csdn.net/qq_34179431/article/details/118571187
感谢大家指正并点赞收藏