"向下转换"unique_ptr <Base>到unique_ptr <Derived>

d7s*_*rai 56 c++ smart-pointers factory-pattern unique-ptr c++11

我有一系列工厂回归unique_ptr<Base>.引擎盖下,虽然,他们所提供的指针各种衍生类型,即unique_ptr<Derived>,unique_ptr<DerivedA>,unique_ptr<DerivedB>

鉴于DerivedA : Derived并且Derived : Base我们有:

unique_ptr<Base> DerivedAFactory() {
    return unique_ptr<Base>(new DerivedA);
}
Run Code Online (Sandbox Code Playgroud)

我需要做的是将指针从返回"转换" unique_ptr<Base>到某个派生级别(不一定是原始的内部级别).用伪代码说明:

unique_ptr<Derived> ptr = static_cast<unique_ptr<Derived>>(DerivedAFactory());
Run Code Online (Sandbox Code Playgroud)

我正在考虑通过从中释放对象unique_ptr,然后使用一个转换原始指针的函数并将其重新分配给另一个unique_ptr所需的风格(release在调用之前由调用者显式完成)来实现这一点:

unique_ptr<Derived> CastToDerived(Base* obj) {
    return unique_ptr<Derived>(static_cast<Derived*>(obj));
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,还是/会有什么时髦吗?


PS.还有一个复杂的问题是,有些工厂驻留在运行时动态加载的DLL中,这意味着我需要确保生成的对象在创建它们的同一个上下文(堆空间)中被销毁.所有权的转移(通常发生在另一个上下文中)必须从原始上下文中提供删除.但除了必须与指针一起提供/转换删除器之外,铸造问题应该是相同的.

Pra*_*ian 44

我创建了几个函数模板,static_unique_ptr_castdynamic_unique_ptr_cast.在你绝对确定指针实际是a的Derived *情况下使用前者,否则使用后者.

template<typename Derived, typename Base, typename Del>
std::unique_ptr<Derived, Del> 
static_unique_ptr_cast( std::unique_ptr<Base, Del>&& p )
{
    auto d = static_cast<Derived *>(p.release());
    return std::unique_ptr<Derived, Del>(d, std::move(p.get_deleter()));
}

template<typename Derived, typename Base, typename Del>
std::unique_ptr<Derived, Del> 
dynamic_unique_ptr_cast( std::unique_ptr<Base, Del>&& p )
{
    if(Derived *result = dynamic_cast<Derived *>(p.get())) {
        p.release();
        return std::unique_ptr<Derived, Del>(result, std::move(p.get_deleter()));
    }
    return std::unique_ptr<Derived, Del>(nullptr, p.get_deleter());
}
Run Code Online (Sandbox Code Playgroud)

该功能正在服用右值引用,以确保你没有从主叫方的脚下拉了地毯unique_ptr传递给你.

  • 您需要从源对象中提取删除器并将其注入目标对象.这种类型很可能是不够的. (6认同)
  • @Praetorian嗨,我一直在尝试使用此功能,并且在初始化unique_ptr(http://pastebin.com/EABRT9G3)时使用自定义删除程序时,它能够正常工作。但是,不确定如何使用默认删除器(http://pastebin.com/BNDBivff)-在这种情况下,编译器会抱怨派生类/基类删除器之间没有可行的转换。是否可以将此代码与默认delterter一起使用?如果是这样,您能否看一下我的第二个粘贴并让我知道我需要如何使用正确的模板参数来调用cast函数?谢谢 :) (2认同)
  • @Malvineous`unique_ptr`构造函数是`noexcept`.但你建议,首先构建第二个`unique_ptr`,然后`release()`原始的所有权,如果复制/移动删除器可以扔掉,将是更加万无一失的选择. (2认同)