unique_ptr smart shared_ptr c++ c++11 smart-pointers factory-pattern unique-ptr

c++ - smart - "Downcasting" unique_ptr<Base> a unique_ptr<Derived>



std shared_ptr (1)

Tengo una serie de fábricas que devuelven unique_ptr<Base> . Sin embargo, bajo el capó están proporcionando punteros a varios tipos derivados, es decir, unique_ptr<Derived> , unique_ptr<DerivedA> , unique_ptr<DerivedB> etc.

Dado DerivedA : Derived y Derived : Base que tendríamos:

unique_ptr<Base> DerivedAFactory() { return unique_ptr<Base>(new DerivedA); }

Lo que tengo que hacer es "convertir" el puntero del unique_ptr<Base> devuelto a algún nivel derivado (no necesariamente el interno interno). Para ilustrar en pseudo código:

unique_ptr<Derived> ptr = static_cast<unique_ptr<Derived>>(DerivedAFactory());

Estoy pensando en hacer esto liberando el objeto del unique_ptr , luego usando una función que arroja el puntero sin unique_ptr y lo reasigna a otro unique_ptr del sabor deseado (el release haría explícitamente la persona que llama antes de la llamada):

unique_ptr<Derived> CastToDerived(Base* obj) { return unique_ptr<Derived>(static_cast<Derived*>(obj)); }

¿Es esto válido, o está / va a haber algo moderno?

PD. Hay una complicación adicional en que algunas de las fábricas residen en DLL que se cargan dinámicamente en tiempo de ejecución, lo que significa que necesito asegurarme de que los objetos producidos se destruyan en el mismo contexto (espacio de pila) a medida que se crearon. La transferencia de propiedad (que normalmente ocurre en otro contexto) debe proporcionar un eliminador del contexto original. Pero aparte de tener que suministrar / lanzar un eliminador junto con el puntero, el problema de la conversión debería ser el mismo.


static_unique_ptr_cast un par de plantillas de funciones, static_unique_ptr_cast y dynamic_unique_ptr_cast . Utilice el primero en los casos en que esté absolutamente seguro de que el puntero es en realidad un Derived * , de lo contrario use el último.

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

Las funciones están tomando una referencia de valor real para asegurarse de no tirar de la alfombra por debajo de los pies de la persona que llama robando el unique_ptr pasaron.