I have a series of factories that return unique_ptr<Base>
. Under the hood, though, they are providing pointers to various derived types, i.e unique_ptr<Derived>
, unique_ptr<DerivedA>
, unique_ptr<DerivedB>
etc.
Given DerivedA : Derived
and Derived : Base
we'd have:
unique_ptr<Base> DerivedAFactory() {
return unique_ptr<Base>(new DerivedA);
}
What I need to do is to "cast" the pointer from the returned unique_ptr<Base>
to some derived level (not necessarily the original internal one). To illustrate in pseudo code:
unique_ptr<Derived> ptr = static_cast<unique_ptr<Derived>>(DerivedAFactory());
I'm thinking of doing this by releasing the object from the unique_ptr
, then using a function that casts the raw pointer and reassigns that to another unique_ptr
of the desired flavor (the release
would be explicitly done by the caller prior to the call):
unique_ptr<Derived> CastToDerived(Base* obj) {
return unique_ptr<Derived>(static_cast<Derived*>(obj));
}
Is this valid, or is / will there be something funky going on?
PS. There is an added complication in that some of the factories reside in DLLs that are dynamically loaded at run-time, which means I need to make sure the produced objects are destroyed in the same context (heap space) as they were created. The transfer of ownership (which typically happens in another context) must then supply a deleter from the original context. But aside from having to supply / cast a deleter along with the pointer, the casting problem should be the same.
CastToDerived
take aunique_ptr<T>&&
. The reason why there are no casts equivalent tostatic_pointer_cast
forshared_ptr
is that casts typically do not modify their argument. But forunique_ptr
, you'd have to move the pointer from the argument to the object returned by the cast. – Vooklesswap
could be a good option too in this case – SchaffelCastToDerived
could be called viaCastToDerived(my_ptr.get())
(which is an error) andCastToDerived(my_ptr.release())
(which is correct). To prevent the former, I suggest using something likeCastToDerived( std::move(my_ptr) )
which is explicit and maybe a bit less error prone. Alternatively, make it explicit in the name, likemove_static_cast<Derived>(my_ptr)
. – Vooklesunique_ptr<T>&&
(or ratherunique_ptr<Derived>&&
, as templated types cannot be exposed across DLL boundaries) would implicitly perform the move / transfer? Could I then just do such a move operation directly without the need for a function? And would such a move retain the deleter from the original unique_ptr? – Skindivemy_ptr.get()
instead. Therefore either enforce the use of astd::move
at the call site or let the cast function move the pointer, but then the name of the cast function needs to convey that it alters its argument. – Vookles