Downcasting shared_ptr vers shared_ptr ?

Update: le shared_ptr dans cet exemple est comme celui de Boost, mais il ne supporte pas shared_polymorphic_downcast (ou dynamic_pointer_cast ou static_pointer_cast d’ailleurs)!

J’essaie d’initialiser un pointeur partagé sur une classe dérivée sans perdre le compte de référence:

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

Jusqu’ici tout va bien. Je ne m’attendais pas à ce que C ++ convertisse implicitement Base * en Derived *. Cependant, je souhaite que les fonctionnalités exprimées par le code (c’est-à-dire le maintien du nombre de références lors de la réduction du pointeur de base). Ma première pensée a été de fournir un opérateur de dissortingbution dans Base afin qu’une conversion implicite en Dérivé puisse avoir lieu (pour les pédants: je vérifierais que la dissortingbution descendante est valide, ne vous inquiétez pas):

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

Eh bien, ça n’a pas aidé. Il semble que le compilateur ait complètement ignoré mon opérateur de transtypage. Des idées sur la façon dont je pourrais faire fonctionner l’affectation shared_ptr? Pour des points supplémentaires: quel type de type Base* const est? const Base* Je comprends, mais Base* const ? A quoi se réfère const dans ce cas?

Vous pouvez utiliser dynamic_pointer_cast . Il est supporté par std::shared_ptr .

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

En outre, je ne recommande pas d’utiliser l’opérateur de dissortingbution dans la classe de base. La diffusion implicite comme celle-ci peut devenir la source de bogues et d’erreurs.

-Update: Si le type n’est pas polymorphe, std::static_pointer_cast peut être utilisé.

Je suppose que vous utilisez boost::shared_ptr … Je pense que vous voulez dynamic_pointer_cast ou shared_polymorphic_downcast .

Celles-ci nécessitent des types polymorphes.

quel type de type Base* const est? const Base* Je comprends, mais Base* const ? A quoi se réfère const dans ce cas?

  • const Base * est un pointeur mutable vers une Base constante.
  • Base const * est un pointeur mutable vers une Base constante.
  • Base * const est un pointeur constant sur une Base mutable.
  • Base const * const est un pointeur constant sur une Base constante.

Voici un exemple minimal:

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

Je ne suis pas sûr qu’il ait été intentionnel que votre exemple crée une instance du type de base et la lance, mais cela sert à illustrer la différence.

Le static_pointer_cast va “juste le faire”. Cela entraînera un comportement indéfini (un Derived* pointant vers la mémoire allouée à et initialisée par Base ) et provoquera probablement un arrêt brutal, voire pire. Le compte de référence sur la base sera incrémenté.

Le dynamic_pointer_cast produira un pointeur nul. Le compte de référence sur la base sera inchangé.

Le shared_polymorphic_downcast aura le même résultat qu’un cast statique, mais déclenchera une assertion, semblant plutôt réussir et conduisant à un comportement indéfini. Le compte de référence sur la base sera incrémenté.

Voir (lien mort) :

Parfois, il est difficile de décider si vous voulez utiliser static_cast ou dynamic_cast , et vous souhaiterez peut-être avoir un peu des deux mondes. Il est bien connu que dynamic_cast a un temps d’exécution, mais il est plus sûr, alors que static_cast n’a pas de surcharge du tout, mais il peut échouer en silence. Comme ce serait bien si vous pouviez utiliser shared_dynamic_cast dans les versions debug et shared_static_cast dans les versions release. Eh bien, une telle chose est déjà disponible et s’appelle shared_polymorphic_downcast .

Si quelqu’un arrive avec boost :: shared_ptr …

C’est ainsi que vous pouvez réduire à Boost shared_ptr. En supposant que Dérivé hérite 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; 

Assurez-vous que la classe / structure 'Base' a au moins une fonction virtuelle. Un destructeur virtuel fonctionne également.