unique_ptr smart shared_ptr make_unique how example c++ boost smart-pointers unique-ptr dynamic-cast

c++ - smart - unique_ptr example



¿Cómo hacer un dynamic_cast con un unique_ptr? (3)

Tengo una jerarquía de clases de la siguiente manera:

class BaseSession : public boost::enable_shared_from_this<BaseSession> class DerivedSessionA : public BaseSession class DerivedSessionB : public BaseSession

Dentro de las funciones de clase derivadas, regularmente llamo funciones como esta:

Func(boost::dynamic_pointer_cast<DerivedSessionA>(shared_from_this()));

Ya que estaba trabajando con shared_ptr para administrar las sesiones, esto estaba funcionando bien. Recientemente, descubrí que mi uso de shared_ptr no es óptimo para este caso. Esto se debe a que estas sesiones son objetos singleton que mantienen un socket por cliente. Si se reconecta el zócalo, las copias de la sesión se utilizan para convertirse en zombies.

Como solución, comencé a pasar shared_ptr por referencia en lugar de copias. Esto solucionó el problema zombie.

Idealmente, sentí que debería usar unique_ptr para almacenar la sesión y luego pasar referencias a otras funciones. Eso abrió toda una lata de gusanos.

¿Cómo puedo convertir un objeto unique_ptr clase base en un objeto unique_ptr de clase derivada? ¿Cuál es la versión unique_ptr de la siguiente línea?

Func(boost::dynamic_pointer_cast<DerivedSessionA>(shared_from_this()));

Solo quiero una copia del objeto de sesión, todo lo demás debería ser una referencia.


Actualizar

La pregunta ha sido aclarada:

Lo siento, no estaba claro. Quiero que la propiedad permanezca con el propietario original, la función llamada solo debe obtener una referencia a ella, no la propiedad. No busco dos punteros inteligentes para el mismo objeto.

En ese caso, la solución es simplemente:

dynamic_cast<B&>(*my_unique_ptr)

Hecho Se tira si el yeso no tiene éxito.

Casting shared_ptr

Para shared_ptr hay std::dynamic_pointer_cast<> ( http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast )

Casting unique_ptr

La forma más simple parecería:

#include <memory> struct A { virtual ~A() = default; }; struct B : A { }; int main() { std::unique_ptr<A> pa(new B); std::unique_ptr<B> pb(dynamic_cast<B*>(pa.release())); // DO NOT DO THIS }

Como el comentarista señala acertadamente, esto puede filtrar el objeto si la conversión falla. Eso no es muy útil.

Una razón por la que dynamic_unique_ptr_cast<> no existe puede ser que el tipo unique_ptr no borre el eliminador. Podría ser difícil / imposible elegir una eliminación adecuada para el tipo de puntero de destino.

Sin embargo, para casos simples, podrías usar algo como esto:

template <typename To, typename From, typename Deleter> std::unique_ptr<To, Deleter> dynamic_unique_cast(std::unique_ptr<From, Deleter>&& p) { if (To* cast = dynamic_cast<To*>(p.get())) { std::unique_ptr<To, Deleter> result(cast, std::move(p.get_deleter())); p.release(); return result; } return std::unique_ptr<To, Deleter>(nullptr); // or throw std::bad_cast() if you prefer } auto pb = dynamic_unique_cast<B>(std::move(pa));


A menos que desee transferir la propiedad de su std::unique_ptr<T> , su función debe llevar el puntero o la referencia a T

Así que la firma de Func debería ser algo como Func(DerivedSessionA*)

y entonces su llamada puede verse como:

std::unique_ptr<BaseSession> ptr; // Initialize it with correct value Func(dynamic_cast<DerivedSessionA*>(ptr.get()));

O como parece llamarlo directamente desde un método en BaseSession :

Func(dynamic_cast<DerivedSessionA*>(this));


Simplemente obtenga el puntero almacenado utilizando el método std::unique_ptr<>::get() :

Func(dynamic_cast<DerivedSessionA*>(shared_from_this().get()))

eso si shared_from_this() tiene ese prototipo:

std::unique_ptr<BaseSession>& shared_from_this();