“Downcasting” unique_ptr a unique_ptr

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

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

 unique_ptr DerivedAFactory() { return unique_ptr(new DerivedA); } 

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

 unique_ptr ptr = static_cast<unique_ptr>(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 CastToDerived(Base* obj) { return unique_ptr(static_cast(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 stack) 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 std::unique_ptr static_unique_ptr_cast( std::unique_ptr&& p ) { auto d = static_cast(p.release()); return std::unique_ptr(d, std::move(p.get_deleter())); } template std::unique_ptr dynamic_unique_ptr_cast( std::unique_ptr&& p ) { if(Derived *result = dynamic_cast(p.get())) { p.release(); return std::unique_ptr(result, std::move(p.get_deleter())); } return std::unique_ptr(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.