调试bad_weak_ptr报错
在网上简单百度了下这个错误,发现大多数说的是下面两种情况
情况1 没有用shared来管理的类
class A:public enable_shared_from_this
{};
int main()
{
A a;
auto p = a.shared_from_this();
}
情况2 在构造函数调用shared_from_this
class A:public enable_shared_from_this
{
A()
{
auto p = shared_from_this();
}
}
然而我的问题不是这两种情况。最后调试了好久终于弄明白问题在哪了,这个过程中也对shared_ptr和enable_shared_from_this的源码看懂了七七八八,对enable_shared_from_this也算是理解了。
所谓的shared_ptr,其实就是在指针和对象之间加了一层。指针要实现计数,总得有个地方保存数字吧。这个地方得让所有指向同一个对象的智能指针都能访问到,那只能是堆了。也就是说,只能指针内部有个指针,指向堆中,那个地方就是放引用计数的地方。这个地方的地址就是关键。enable_shared_form_this要解决的,就是类自己怎么知道那个放引用计数的地方在哪?通过继承enable_shared_form_this,其实继承了一个名字为_M_weak_this的weak_ptr指针。这个指针就是要指向对象自己的指针,当需要shared_from_this的时候,返回的就是用这个weakptr初始化构造成的sharedptr。
我最开始看源代码很奇怪没找到哪里有初始化这个weakptr的地方啊。enable_shared_from_this的源代码很少,如下
template<typename _Tp>
class enable_shared_from_this
{
protected:
constexpr enable_shared_from_this() noexcept { }
enable_shared_from_this(const enable_shared_from_this&) noexcept { }
enable_shared_from_this&
operator=(const enable_shared_from_this&) noexcept
{ return *this; }
~enable_shared_from_this() { }
public:
shared_ptr<_Tp>
shared_from_this()
{ return shared_ptr<_Tp>(this->_M_weak_this); }
shared_ptr<const _Tp>
shared_from_this() const
{ return shared_ptr<const _Tp>(this->_M_weak_this); }
#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
#define __cpp_lib_enable_shared_from_this 201603
weak_ptr<_Tp>
weak_from_this() noexcept
{ return this->_M_weak_this; }
weak_ptr<const _Tp>
weak_from_this() const noexcept
{ return this->_M_weak_this; }
#endif
private:
template<typename _Tp1>
void
_M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept
{ _M_weak_this._M_assign(__p, __n); }
// Found by ADL when this is an associated class.
friend const enable_shared_from_this*
__enable_shared_from_this_base(const __shared_count<>&,
const enable_shared_from_this* __p)
{ return __p; }
template<typename, _Lock_policy>
friend class __shared_ptr;
mutable weak_ptr<_Tp> _M_weak_this;
};
后来看了一些文章才明白,这个初始化是在shareptr的构造函数中完成的。在sharedptr的构造函数中,会检测要构造的对象是否继承了enable_shared_from_this.如果继承了这个类,就会对这个类中的_M_weak_this赋值,让这个weakptr中记录下来sharedptr保存引用计数的地方的内存地址。从而实现了功能。
这里是怎么判断对象有没有继承enable_shared_from_this呢?
template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
typename enable_if<__has_esft_base<_Yp2>::value>::type
_M_enable_shared_from_this_with(_Yp* __p) noexcept
{
if (auto __base = __enable_shared_from_this_base(_M_refcount, __p))
__base->_M_weak_assign(const_cast<_Yp2*>(__p), _M_refcount);
}
template<typename _Yp, typename _Yp2 = typename remove_cv<_Yp>::type>
typename enable_if<!__has_esft_base<_Yp2>::value>::type
_M_enable_shared_from_this_with(_Yp*) noexcept
{ }
如上的两个函数,分别是给继承了enable_shared_from_this和没继承enable_shared_from_this用的。可以看到是用模板的方法,在编译期实现的。不过具体这个__has_esft_base是怎么做到的,我没太看懂。模板真的是黑魔法。
我遇到的问题就是在这一步,应该执行上一个函数,结果执行的却是下面的函数。这说明我没有正确继承enable_shared_from_this啊!我翻回去一看,原来是因为我没有公有继承。c++默认不写的话就是私有继承。终于找到问题所在了。