C++ 如何从父级和派生级的\u启用\u共享\u
我有一个简单的基类和派生类,我希望这两个类都有C++ 如何从父级和派生级的\u启用\u共享\u,c++,boost,smart-pointers,C++,Boost,Smart Pointers,我有一个简单的基类和派生类,我希望这两个类都有shared\u from\u this() 这个简单的解决方案: class foo : public enable_shared_from_this<foo> { void foo_do_it() { cout<<"foo::do_it\n"; } public: virtual function<void()> get_callback() {
shared\u from\u this()
这个简单的解决方案:
class foo : public enable_shared_from_this<foo> {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&foo::foo_do_it,shared_from_this());
}
virtual ~foo() {};
};
class bar1 : public foo , public enable_shared_from_this<bar1> {
using enable_shared_from_this<bar1>::shared_from_this;
void bar1_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar1::bar1_do_it,shared_from_this());
}
};
class bar2 : public foo {
void bar2_do_it()
{
cout<<"foo::do_it\n";
}
shared_ptr<bar2> shared_from_this()
{
return boost::static_pointer_cast<bar2>(foo::shared_from_this());
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar2::bar2_do_it,shared_from_this());
}
};
所以在“谷歌搜索”之后,我找到了以下解决方案:
class foo : public enable_shared_from_this<foo> {
void foo_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&foo::foo_do_it,shared_from_this());
}
virtual ~foo() {};
};
class bar1 : public foo , public enable_shared_from_this<bar1> {
using enable_shared_from_this<bar1>::shared_from_this;
void bar1_do_it()
{
cout<<"foo::do_it\n";
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar1::bar1_do_it,shared_from_this());
}
};
class bar2 : public foo {
void bar2_do_it()
{
cout<<"foo::do_it\n";
}
shared_ptr<bar2> shared_from_this()
{
return boost::static_pointer_cast<bar2>(foo::shared_from_this());
}
public:
virtual function<void()> get_callback()
{
return boost::bind(&bar2::bar2_do_it,shared_from_this());
}
};
class bar2:公共foo{
void bar2_do_it()
{
对不起,没有
问题是shared_ptr
和shared_ptr
是不同的类型。我不理解引擎盖下发生的一切,但我认为当构造函数返回并被分配到shared_ptr
时,内部弱_ptr
会看到没有任何东西指向它(因为只有一个shared\u ptr
会增加计数器)并重置自身。当您在get\u回调中从该调用bar1::shared\u时,会出现异常,因为内部弱\u ptr
没有指向任何东西
本质上,enable\u shared\u from\u此
似乎只能从层次结构中的单个类透明地工作。如果您尝试,问题应该会变得很明显。通过在基类上定义以下内容,OP解决方案可以变得更加方便
protected:
template <typename Derived>
std::shared_ptr<Derived> shared_from_base()
{
return std::static_pointer_cast<Derived>(shared_from_this());
}
受保护:
模板
std::shared_ptr shared_from_base()
{
返回std::static_pointer_cast(来自_this()的共享_);
}
一个类似于@evoskuil的解决方案,它可以减少派生类中的样板文件,如果您想实现一个shared\u from\u this()
函数,则会在类中的使用点生成以下代码:
auto shared_from_this() {
return shared_from(this);
}
这在类之外使用了“shim”函数。通过这种方式,它还为不能修改接口但从派生的类提供了一种干净的方法,可以从该类启用共享\u
auto shared_that = shared_from(that);
注意:此处对返回类型使用auto
取决于编译器的使用年限
可以放置在库标题中的填充函数:
template <typename Base>
inline std::shared_ptr<Base>
shared_from_base(std::enable_shared_from_this<Base>* base)
{
return base->shared_from_this();
}
template <typename Base>
inline std::shared_ptr<const Base>
shared_from_base(std::enable_shared_from_this<Base> const* base)
{
return base->shared_from_this();
}
template <typename That>
inline std::shared_ptr<That>
shared_from(That* that)
{
return std::static_pointer_cast<That>(shared_from_base(that));
}
编译测试:
struct base : public std::enable_shared_from_this<base> {};
struct derived : public base
{
auto shared_from_this() {
return shared_from(this);
}
// Can also provide a version for const:
auto shared_from_this() const {
return shared_from(this);
}
// Note that it is also possible to use shared_from(...) from
// outside the class, e.g.
// auto sp = shared_from(that);
};
template <typename X>
struct derived_x : public derived
{
auto shared_from_this() {
return shared_from(this);
}
};
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
auto const& const_pderived = *pderived;
const_pderived.shared_from_this();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}
intmain()
{
auto pbase=std::使_共享();
auto-pderived=std::make_shared();
auto-pderived_x=std::make_shared();
自动常数&const_pderived=*pderived;
const_pderived.shared_from_this();
std::shared_ptr test1=pbase->shared_from_this();
std::shared_ptr test2=pderived->shared_from_this();
std::shared_ptr test3=pderived_x->shared_from_this();
返回0;
}
我发布的先前解决方案旨在使评论仍然有意义-这将函数放置在基类中,存在一些问题-特别是“普通”类和模板类所需实现之间的不一致性。
此外,对于新的类层次结构,基类中的实现需要重复进行,而新的类层次结构并不是那么枯燥。
此外,基类函数还可能因从不同的对象提供基类指针而被误用。上面较新的方案完全避免了这一点,运行时断言(…)检查也会进行
旧的实施:
#include <cassert>
#include <memory>
class base : public std::enable_shared_from_this<base>
{
protected:
template <typename T>
std::shared_ptr<T> shared_from(T* derived) {
assert(this == derived);
return std::static_pointer_cast<T>(shared_from_this());
}
};
class derived : public base
{
public:
auto shared_from_this() {
return shared_from(this);
}
};
template <typename X>
class derived_x : public derived
{
public:
auto shared_from_this() {
return this->template shared_from(this);
}
};
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}
#包括
#包括
类基:public std::从\u中启用\u共享\u
{
受保护的:
模板
std::shared_ptr shared_from(T*派生){
断言(this==派生);
返回std::static_pointer_cast(来自_this()的共享_);
}
};
派生类:公共基
{
公众:
从_this()自动共享_{
从(此)返回共享的_;
}
};
模板
类派生的\u x:公共派生的
{
公众:
从_this()自动共享_{
从(此)返回此->模板共享\u;
}
};
int main()
{
auto pbase=std::使_共享();
auto-pderived=std::make_shared();
auto-pderived_x=std::make_shared();
std::shared_ptr test1=pbase->shared_from_this();
std::shared_ptr test2=pderived->shared_from_this();
std::shared_ptr test3=pderived_x->shared_from_this();
返回0;
}
我尝试手动实现它,实际上并不难。在My::SmartPointer
中,检查T是否派生自My::enableSmartFromThis
。如果是,不要在堆上分配引用计数器,而是使用My::enableSmartFromThis
的成员。现在My::GetSmartFromThis(this)
变得微不足道,它可以将此
转换为My::enableSmartFromThis*
并找到现有的引用计数。您甚至可以检查您是否正在尝试从基转换为派生,而仅从My::enableSmartFromThis
派生。这非常优雅。+1您为什么使用模板
关键字inderived_x
?@Myon这是因为shared_from是基类中的模板成员函数,它是从模板类中调用的。如果没有此处的“this”或“template”关键字,它将无法在兼容的编译器上编译。旧版本的MSVC可能编译得很好。没有它,编译器将解释“@Myon实际上想出了一个更好的方法,完全避免了丑陋的模板类不一致性,并且还有许多其他积极的副作用-参见更新的答案。