18

我使用 shared_ptr 和 enable_shared_from_this 玩了一会儿,但遇到了一些我不太了解的东西。

在我的第一次尝试中,我构建了这样的东西:

class shared_test : std::enable_shared_from_this<shared_test> {
public:
    void print(bool recursive) {
        if (recursive) {
            shared_from_this()->print(false);
        }

        std::cout << "printing" << std::endl;
    }
};

请注意,此类正在私下扩展 std::enable_shared_from_this。这显然有很大的不同,因为执行这样的事情:

int main() {
    auto t(std::make_shared<shared_test>());
    t->print(true);
    return 0;
}

引发 bad_weak_ptr 异常。好像我将类定义更改为从 std::enable_shared_from_this 公开的固有的,这只是查找。

为什么会这样,我在这里想念什么?并且没有办法让它适用于私有继承,因为 shared_test 类的“外部世界”不需要知道它正在启用共享......(至少,如果你问我,还是我又错过了什么?)

4

4 回答 4

14

为什么会这样,我在这里想念什么?

要使shared_from_this工作enable_shared_from_this必须知道shared_ptr哪个拥有班级。在您的 STL 实现中它是weak_ptr,通过其他实现是可能的。当您私有继承时,就无法从类外部访问基类的属性。实际上,甚至不可能理解你是从那里继承下来的。因此make_shared生成通常的 shared_ptr 初始化而不在enable_shared_from_this.

由于未正确初始化,异常不是来自make_shared而是形式引发。shared_from_thisenable_shared_from_this

并且没有办法使它适用于私有继承,因为 shared_test 类的“外部世界”不需要知道它正在启用共享...

不,外部世界必须知道对象与 shared_ptr 有特殊关系才能正常工作。

于 2016-10-08T20:40:44.787 回答
7

没有办法让它适用于私有继承,因为 shared_test 类的“外部世界”不需要知道它正在启用共享

shared_ptr它本身就是“外部世界”的一部分;shared_ptr构造函数需要能够访问它指向的对象的基enable_shared_from_this类子shared_test对象,以便初始化实现的私有weak_ptr成员enable_shared_from_this

于 2016-10-08T20:45:52.673 回答
1

我从 STL 中的代码分析这个问题:

自动 t(std::make_shared());

代码行构造一个shared_ptr;首先我们深入make_shared函数

 // FUNCTION TEMPLATE make_shared
   template<class _Ty,
   class... _Types>
   NODISCARD inline shared_ptr<_Ty> make_shared(_Types&&... _Args)
   {    // make a shared_ptr
     const auto _Rx = new _Ref_count_obj<_Ty>(_STD forward<_Types>(_Args)...);

     shared_ptr<_Ty> _Ret;
    _Ret._Set_ptr_rep_and_enable_shared(_Rx->_Getptr(), _Rx);
     return (_Ret);
   }

注意:我们深入了解函数_Ret.Set_ptr_rep_and_enable_shared。我们可以看到以下内容:

template<class _Ux>
   void _Set_ptr_rep_and_enable_shared(_Ux * _Px, _Ref_count_base * _Rx)
   {    // take ownership of _Px
        this->_Set_ptr_rep(_Px, _Rx);
        _Enable_shared_from_this(*this, _Px);
   }

所以我们找到函数 _Enable_shared_from_this ,继续:

 template<class _Other,
    class _Yty>
    void _Enable_shared_from_this(const shared_ptr<_Other>& _This, _Yty * _Ptr)
    {   // possibly enable shared_from_this
    _Enable_shared_from_this1(_This, _Ptr, _Conjunction_t<
        negation<is_array<_Other>>,
        negation<is_volatile<_Yty>>,
        _Can_enable_shared<_Yty>>{});
   }

我们找到一个关键点:_Can_enable_shared<_Yty>

template<class _Yty,
    class = void>
    struct _Can_enable_shared
        : false_type
    {   // detect unambiguous and accessible inheritance from enable_shared_from_this
    };

template<class _Yty>
    struct _Can_enable_shared<_Yty, void_t<typename _Yty::_Esft_type>>
        : is_convertible<remove_cv_t<_Yty> *, typename _Yty::_Esft_type *>::type
    {   // is_convertible is necessary to verify unambiguous inheritance
    };

我们发现只有 _Yty 有 _Esft_type 并且 _Yty 可以转换为 _Esft_type,可以 _Yty 可以启用_shared(如果你想了解更多,那就是在 _Yty 中设置weak_ptr,否则你可能会在使用 shared_from_this 时遇到 bad_weak_ptr 错误)。那么_Esft_type 是什么?

 template<class _Ty>
    class enable_shared_from_this
    {   // provide member functions that create shared_ptr to this
public:
    using _Esft_type = enable_shared_from_this;
     ...
   }

所以_Esft_type只是表示enable_shared_from_this<_Ty>,所以如果你使用private继承,外面不仅看不到_Esft_type而且_Yt不能转换成_Esft_type。所以weak_ptr 不能被设置,所以bad_weak_ptr 可能会被调用。

所以外部需要知道_Esft_type的存在,所以在构造shared_ptr时,也可以设置shared_test的weak_ptr。

于 2018-05-30T01:14:32.013 回答
0

根据文档,为了“shared_from_this”成员函数的可访问性,必须公开继承。

“从 std::enable_shared_from_this 公开继承为类型 T 提供了一个成员函数 shared_from_this” - 来自 CPP 参考 http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

shared_from_this:

返回一个shared_ptr,它共享*this(公共成员函数)的所有权

于 2016-10-08T20:42:28.083 回答