我正在玩一些使用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类不需要知道它正在启用此共享...(至少,如果你问我,或者我再次错过了什么?)
答案 0 :(得分:9)
为什么会这样,我在这里想念什么?
要使shared_from_this
工作enable_shared_from_this
必须了解持有该课程的shared_ptr
。在您的STL实现中它是weak_ptr
,通过其他实现是可能的。当您私下继承时,则无法从类外部访问基类的属性。实际上甚至不可能理解你继承了。因此,make_shared
会生成常规的shared_ptr初始化,而无需在enable_shared_from_this
中设置适当的字段。
异常不是来自make_shared
,而是来自shared_from_this
,因为enable_shared_from_this
未正确初始化。
并且没有办法让它适用于私有继承,因为shared_test类的“外部世界”不需要知道它是从这个开始共享...
没有。外界必须知道该对象与shared_ptr有特殊关系才能正常工作。
答案 1 :(得分:5)
是不是有办法使它适用于私有继承,因为shared_test类的“外部世界”不需要知道它是从此启用共享
shared_ptr
本身就是“外部世界”的一部分; enable_shared_from_this
构造函数需要能够访问它指向的shared_test
对象的weak_ptr
基类子对象,以便初始化{{enable_shared_from_this
的私有moment.unix(1440187622).fromNow()
成员1}}实施。
答案 2 :(得分:0)
根据文档,必须公开继承“shared_from_this”成员函数的accessiblity。
“公开继承自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的所有权 (公共成员职能)
答案 3 :(得分:0)
我从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&lt; _Yty&gt;
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可以是enable_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&lt; _Ty&gt;,所以如果你使用私有继承,外面不仅看不到_Esft_type而_Yt也不能转换为_Esft_type。所以不能设置weak_ptr所以可以调用bad_weak_ptr。
所以外部需要知道_Esft_type的存在,所以当构造shared_ptr时,也可以设置shared_test的weak_ptr。