C++ 模糊地指向堆或堆栈对象的智能指针

C++ 模糊地指向堆或堆栈对象的智能指针,c++,c++11,smart-pointers,C++,C++11,Smart Pointers,我的一个应用程序将从std::unique_ptr的变体中获益匪浅,该变体可以配置为不总是假定所指向对象的所有权 考虑以下类层次结构: class AbstractFoo { ... }; template<typename T> Foo : public AbstractFoo { Foo( const AbstractFoo& absFoo ) { ... } ... }; 其中类make_unique_ptr具有类似于std::unique_p

我的一个应用程序将从std::unique_ptr的变体中获益匪浅,该变体可以配置为不总是假定所指向对象的所有权

考虑以下类层次结构:

class AbstractFoo { ... };

template<typename T> Foo : public AbstractFoo 
{
    Foo( const AbstractFoo& absFoo ) { ... } 
    ... 
};
其中类
make_unique_ptr
具有类似于
std::unique_ptr
的构造函数,但具有可选的布尔参数,该参数指定指针是否应属于智能指针


对于这种情况,是否有最佳实践解决方案?我希望避免返回原始指针,因为如果在手动删除对象之前引发异常,可能会导致内存泄漏。

您可以将
共享\u 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
}
模板
共享ptr转换(AbstractFoo和absFoo)
{
if(Foo*Foo=dynamic_cast(&absFoo))
返回共享的_ptr(foo,[](foo*){});//不执行任何操作删除
其他的
return make_shared(absFoo);//常规删除器
}
更新:当我输入这个时,程序设计师杰克显然在评论中写了同样的想法。如果你想写它作为答案,我会删除我的。

我认为这个设计很脆弱:


shared\u ptr
有效吗?(您可能需要
AbstractFoo
来实现
从这个
启用共享的\u,或者将
共享的\u ptr
传递给
转换
,而不是引用)。是的,
共享的\u ptr
似乎就是这种情况,它完全按照您所说的做:并不总是承担所有权,并相应地进行行为。您的布尔标志在
共享的\u ptr
的引用计数器中有一个隐式等价物。另一种可能是,即使对象类型正确,也要始终克隆该对象,但如果可能,也可以提供一种廉价快速的克隆方法。@dlf根据,您建议的两种方法都要求对象已经由
共享\u ptr
管理。不幸的是,这非常具有侵入性,我希望智能指针的使用仅限于我的库实现中。@JackPoulson是的,这是真的。如果这是一个交易破坏者,你将需要其他东西(比如BartoszKP的建议,总是创建一个克隆,但要使克隆便宜)。使用一个带有空删除器的智能指针怎么样?只有当代码未能删除传递给
Convert
的原始
AbstractFoo&
时,它才会泄漏,以前也是这样。否则,引用计数将像往常一样上下移动,直到达到0,此时……什么也不会发生。:)@BartoszKP否,返回的对象将具有与参数相同的生存期
Convert
函数只是一个实用函数,用于库中的内部使用。要求使用智能指针包装输入具有外部影响。此外,您提出了一个关于不接受常量引用输入的好观点,因此我修改为接受指针。
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
}
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) );
}
// 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 );