我有一系列工厂返回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);
}
我需要做的是将指针从返回的unique_ptr<Base>
“转换”到某个派生级别(不一定是原始的内部级别)。用伪代码说明:
unique_ptr<Derived> ptr = static_cast<unique_ptr<Derived>>(DerivedAFactory());
我正在考虑通过从unique_ptr
释放对象,然后使用一个转换原始指针的函数并将其重新分配给所需风格的另一个unique_ptr
({{1}将在调用之前由调用者明确地完成:
release
这是否有效,或者/是否会有一些时髦的事情发生?
PS。还有一个复杂的问题是,一些工厂驻留在运行时动态加载的DLL中,这意味着我需要确保生成的对象在创建时在相同的上下文(堆空间)中被销毁。所有权的转移(通常发生在另一个上下文中)必须从原始上下文中提供删除。但除了必须提供/转换删除器和指针之外,投射问题应该是相同的。
答案 0 :(得分:39)
我会创建一些功能模板,static_unique_ptr_cast
和dynamic_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
来拉出来自呼叫者脚下的地毯。