Smart pointers that ambiguously point to a heap or stack object

One of my applications will greatly benefit from an option std::unique_ptr<T>that can be configured to not always take responsibility for the object that it points to.

Consider the following class hierarchy:

class AbstractFoo { ... };

template<typename T> Foo : public AbstractFoo 
{
    Foo( const AbstractFoo& absFoo ) { ... } 
    ... 
};

and an API that standardizes each host procedure AbstractFooand, if necessary, translates into specific instances Foo<T>. In cases where the reference to AbstractFoois actually an instance of the corresponding derived type, only a is required dynamic_cast, and no data needs to be copied. However, when the abstract link is of the wrong type, you must do nontrivial work to create a copy in the requested format.

My desired interface would look like this:

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 );
    ...
}

where the class make_unique_ptr<T>has a constructor similar std::unique_ptr<T>, but with an optional boolean argument that indicates whether the pointer should be the owner of a smart pointer or not.

Is there a best practice for this situation? I would prefer not to return a raw pointer, as this could lead to a memory leak if an exception is thrown before the object is deleted manually.

+4
source share
2 answers

You can use shared_ptrin combination with user deletion:

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, , , . , .

+4

, :

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 dlf )... , Convert smart_foo_cast somesuch, imho .

AbstractFoo* ( API). , const AbstractFoo&, , const& .


, ​​ () "" , unique_ptr arg "".

// 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 );
+2

All Articles