"Downcasting" unique_ptr<Base>到unique_ptr<Derived>

"Downcasting" unique_ptr<Base> to unique_ptr<Derived>

本文关键字:unique gt lt ptr Derived Base Downcasting      更新时间:2023-10-16

我有一系列返回unique_ptr<Base>的工厂。不过,在后台,它们提供了指向各种派生类型的指针,即unique_ptr<Derived>unique_ptr<DerivedA>unique_ptr<DerivedB>等。

给定DerivedA : DerivedDerived : Base,我们会得到:

unique_ptr<Base> DerivedAFactory() {
return unique_ptr<Base>(new DerivedA);
}

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

unique_ptr<Derived> ptr = static_cast<unique_ptr<Derived>>(DerivedAFactory());

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

unique_ptr<Derived> CastToDerived(Base* obj) {
return unique_ptr<Derived>(static_cast<Derived*>(obj));
}

这是有效的吗,还是会有什么奇怪的事情发生?


PS。还有一个更复杂的问题是,一些工厂位于运行时动态加载的DLL中,这意味着我需要确保生成的对象在创建时的相同上下文(堆空间)中被销毁。所有权的转移(通常发生在另一个上下文中)必须从原始上下文中提供委托人。但是,除了必须随指针一起提供/强制转换deleter之外,强制转换问题应该是一样的

我会创建两个函数模板static_unique_ptr_castdynamic_unique_ptr_cast。在绝对确定指针实际上是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());
}

函数采用右值引用,以确保您不会因为窃取传递给您的unique_ptr而从呼叫者的脚下拉开地毯。