我的一个应用程序将从std::unique_ptr<T>
的变体中受益匪浅,它可以配置为不总是假定所指向对象的所有权。
考虑以下类层次结构:
class AbstractFoo { ... };
template<typename T> Foo : public AbstractFoo
{
Foo( const AbstractFoo& absFoo ) { ... }
...
};
和一个API,它标准化每个接受AbstractFoo
的例程并根据需要转换为Foo<T>
的特定实例。如果对AbstractFoo
的引用实际上已经是正确派生类型的实例,则只需要dynamic_cast
并且不需要复制任何数据。但是,当抽象引用属于不正确类型时,需要执行非平凡的工作来创建所请求格式的副本。
我想要的界面如下:
template<typename T>
my_unique_ptr<Foo<T>> Convert( AbstractFoo& absFoo )
{
if( Foo<T>* foo = dynamic_cast<Foo<T>*>(&absFoo) )
return my_unique_ptr<Foo<T>>( foo, false );
else
return my_unique_ptr<Foo<T>>( new Foo<T>(absFoo) );
}
void Bar( AbstractFoo& absFoo )
{
my_unique_ptr<Foo<T>> ptr = Convert<T>( absFoo );
...
}
其中类make_unique_ptr<T>
有一个类似于std::unique_ptr<T>
的构造函数,但是带有一个可选的boolean参数,用于指定指针是否应归智能指针所有。
对于这种情况,是否有最佳实践解决方案?我宁愿避免返回原始指针,因为如果在手动删除对象之前抛出异常,它可能会导致内存泄漏。
答案 0 :(得分:4)
您可以将shared_ptr
与自定义删除器一起使用:
template<typename T>
shared_ptr<Foo<T>> Convert( AbstractFoo& absFoo )
{
if( Foo<T>* foo = dynamic_cast<Foo<T>*>(&absFoo) )
return shared_ptr<Foo<T>>( foo, [](Foo<T>*){} ); // do-nothing deleter
else
return make_shared<Foo<T>>( absFoo ); // regular deleter
}
更新:programmerjake显然在我输入时在评论中写了相同的想法。如果你想把它写成答案,我会删除我的。
答案 1 :(得分:2)
我认为这个设计是 broken 脆弱:
template<typename T> my_unique_ptr<Foo<T>> Convert( AbstractFoo& absFoo ) { if( Foo<T>* foo = dynamic_cast<Foo<T>*>(absFoo) ) return my_unique_ptr<Foo<T>>( foo, false ); else return my_unique_ptr<Foo<T>>( new Foo<T>(absFoo) ); }
在if
路径中,您创建一个与absFoo
参数的生命周期相关联的对象。
在else
路径中,您创建的对象与任何其他对象的生命周期无关。
来电者无法区分这两种情况 - 这似乎相当脆弱。
至于仍在使用它(shared_ptr
与Convert
一样)...
也许smart_foo_cast
可以被称为AbstractFoo*
或者某些人,那么一生中的东西就会更明显地显示出来。
就个人而言,我也需要const AbstractFoo&
(这种改变不会影响外部API)。只需确保永远不会让它const&
,因为您永远不知道unique_ptr
何时可能是隐含的临时。
如果你可以(可选)&#34;沉没&#34;你的问题就会消失。使用// Caller always yields ownership of absFoo:
template<typename T>
unique_ptr<Foo<T>> Convert( unique_ptr<AbstractFoo> absFoo );
// Caller may yield ownership of absFoo:
// (Caller needs to check whether absFoo was moved-from)
template<typename T>
unique_ptr<Foo<T>> Convert( unique_ptr<AbstractFoo>& absFoo );
// Caller may share ownership of absFoo with return value:
template<typename T>
shared_ptr<Foo<T>> Convert( const shared_ptr<AbstractFoo>& absFoo );
作为arg或&#34;分享&#34;论证。
{{1}}