Downcasting shared_ptr a shared_ptr ?

Actualización: el shared_ptr en este ejemplo es como el de Boost, pero no es compatible con shared_polymorphic_downcast (o dynamic_pointer_cast o static_pointer_cast para el caso).

Intento inicializar un puntero compartido a una clase derivada sin perder el recuento de referencias:

struct Base { }; struct Derived : public Base { }; shared_ptr base(new Base()); shared_ptr derived; // error: invalid conversion from 'Base* const' to 'Derived*' derived = base; 

Hasta aquí todo bien. No esperaba que C ++ implícitamente convirtiera Base * en Derived *. Sin embargo, sí quiero la funcionalidad expresada por el código (es decir, mantener el recuento de referencias mientras se baja el puntero base). Mi primer pensamiento fue proporcionar un operador de reparto en Base para que pudiera tener lugar una conversión implícita a Derived (para pedantes: comprobaría que el lanzamiento descendente es válido, no se preocupe):

 struct Base { operator Derived* (); } // ... Base::operator Derived* () { return down_cast(this); } 

Bueno, no ayudó. Parece que el comstackdor ignoró por completo a mi operador de typecast. ¿Alguna idea de cómo podría hacer que la asignación shared_ptr funcione? Para puntos extra: ¿qué tipo de tipo Base* const es? const Base* Lo entiendo, pero Base* const ? ¿A qué se refiere const en este caso?

Puede usar dynamic_pointer_cast . Es compatible con std::shared_ptr .

 std::shared_ptr base (new Derived()); std::shared_ptr derived = std::dynamic_pointer_cast (base); 

Además, no recomiendo usar el operador de reparto en la clase base. Los lanzamientos implícitos como este pueden convertirse en la fuente de errores y errores.

-Update: si el tipo no es polimórfico, se puede usar std::static_pointer_cast .

Supongo que estás utilizando boost::shared_ptr … Creo que quieres dynamic_pointer_cast o shared_polymorphic_downcast .

Sin embargo, estos requieren tipos polimórficos.

¿Qué tipo de tipo Base* const es? const Base* Lo entiendo, pero Base* const ? ¿A qué se refiere const en este caso?

  • const Base * es un puntero mutable a una Base constante.
  • Base const * es un puntero mutable a una Base constante.
  • Base * const es un puntero constante a una Base mutable.
  • Base const * const es un puntero constante a una Base constante.

Aquí hay un ejemplo mínimo:

 struct Base { virtual ~Base() { } }; // dynamic casts require polymorphic types struct Derived : public Base { }; boost::shared_ptr base(new Base()); boost::shared_ptr derived; derived = boost::static_pointer_cast(base); derived = boost::dynamic_pointer_cast(base); derived = boost::shared_polymorphic_downcast(base); 

No estoy seguro si fue intencional que tu ejemplo crea una instancia del tipo base y lo lanza, pero sirve para ilustrar la diferencia muy bien.

El static_pointer_cast “simplemente lo hará”. Esto dará como resultado un comportamiento indefinido (un Derived* apuntando a la memoria asignada e inicializada por Base ) y probablemente causará un locking, o algo peor. El recuento de referencia en la base se incrementará.

El dynamic_pointer_cast dará como resultado un puntero nulo. El recuento de referencias en la base cambiará.

shared_polymorphic_downcast tendrá el mismo resultado que un lanzamiento estático, pero activará una afirmación, en lugar de tener éxito y conducir a un comportamiento indefinido. El recuento de referencia en la base se incrementará.

Ver (enlace muerto) :

A veces es un poco difícil decidir si usar static_cast o dynamic_cast , y desearía poder tener un poco de ambos mundos. Es bien sabido que dynamic_cast tiene una sobrecarga de tiempo de ejecución, pero es más seguro, mientras que static_cast no tiene ninguna sobrecarga, pero puede fallar silenciosamente. Qué bueno sería si pudiera usar shared_dynamic_cast en las comstackciones de depuración y shared_static_cast en las comstackciones de lanzamiento. Bueno, tal cosa ya está disponible y se llama shared_polymorphic_downcast .

Si alguien llega aquí con boost :: shared_ptr …

Esta es la forma en que puede bajar a Boost shared_ptr derivado. Suponiendo que Derived hereda de Base.

 boost::shared_ptr bS; bS.reset(new Derived()); boost::shared_ptr dS = boost::dynamic_pointer_cast(bS); std::cout << "DerivedSPtr is: " << std::boolalpha << (dS.get() != 0) << std::endl; 

Asegúrese de que la clase / estructura 'Base' tenga al menos una función virtual. Un destructor virtual también funciona.