在网上简单百度了下这个错误,发现大多数说的是下面两种情况

情况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++默认不写的话就是私有继承。终于找到问题所在了。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注