Question

Existe-t-il une bonne pratique relative à la gestion des erreurs dynamic_cast (sauf de ne pas l'utiliser si vous n'êtes pas obligé de le faire)? Je me demande comment je devrais aller à propos de NULL et bad_cast qu'il peut lancer. Devrais-je vérifier pour les deux? Et si j'attrape bad_cast ou détecte NULL, je ne pourrai probablement pas récupérer de toute façon ... Pour le moment, j'utilise assert pour vérifier si dynamic_cast n'a pas renvoyé de valeur NULL. Accepteriez-vous cette solution lors d’une révision du code?

Était-ce utile?

La solution

Si le dynamic_cast devait réussir, il serait judicieux d'utiliser boost::polymorphic_downcast à la place, ce qui donne un petit quelque chose comme ceci:

assert(dynamic_cast<T*>(o) == static_cast<T*>(o));
return static_cast<T*>(o);

De cette façon, vous détecterez les erreurs dans la version de débogage tout en évitant les temps d’exécution lors de la génération d’une version.

Si vous pensez que la conversion peut échouer et que vous souhaitez le détecter, utilisez bad_cast et convertissez en un type de référence. Cette distribution lancera if en cas d’erreur et arrêtera votre programme. (C’est bien si, comme vous le dites, vous n’allez pas récupérer de toute façon)

T& t = dynamic_cast<T&>(o);
t.func(); //< Use t here, no extra check required

Utilisez assert un type de pointeur uniquement si le pointeur 0 a un sens dans le contexte. Vous voudrez peut-être l'utiliser dans un <=> comme ceci:

if (T* t = dynamic_cast<T*>(o)) {
    t->func(); //< Use t here, it is valid
}
// consider having an else-clause

Avec cette dernière option, vous devez vous assurer que le chemin d'exécution a un sens si le <=> renvoie 0.

Pour répondre directement à votre question: je préférerais l’une des deux premières alternatives que j’ai données à un <=> explicite dans le code:)

Autres conseils

bad_cast n'est renvoyé que lors de la diffusion de références

dynamic_cast< Derived & >(baseclass)

NULL est renvoyé lors de la diffusion de pointeurs

dynamic_cast< Derived * >(&baseclass)

Il n'y a donc jamais besoin de vérifier les deux.

Assert peut être acceptable, mais cela dépend en grande partie du contexte. Encore une fois, c’est vrai pour à peu près tous les assertions ...

Oui et non.

boost::polymorphic_downcast<> est sûrement une bonne option pour gérer les erreurs de dynamic_cast<> lors de la phase de débogage. Toutefois, il convient de mentionner que polymorphic_downcast<> ne doit être utilisé que lorsqu'il est possible de prédire le type polymorphe passé au moment de la compilation , sinon le <=> doit être utilisé à la place.

Cependant, une séquence de:

if (T1* t1 = dynamic_cast<T1*>(o)) 
{ }
if (T2* t2 = dynamic_cast<T2*>(o)) 
{ }
if (T3* t3 = dynamic_cast<T3*>(o)) 
{ }

désigne un très mauvais design qui devrait être réglé par polymorphisme et par fonctions virtuelles .

Cela dépend ...; -)

Si je m'attendais vraiment à ce que dynamic_cast me donne quelque chose de utilisable, par exemple si moi-même et personne d'autre n'a ajouté un type polymorphe à un conteneur de pointeurs vers une classe de base, j'utiliserais alors la conversion de référence et laisser std::bad_cast tuer mon application - il n'y aurait pas grand-chose à faire, vraiment.

Cependant, si j'interroge un type polymorphe sur une capacité exposée par une interface qu'elle n'a pas nécessairement à implémenter, alors j'utiliserais le transtideur de pointeur, puis une valeur NULL ne serait pas une erreur ( À moins, bien sûr, que je s’attende à ce que la capacité soit vraiment d’être présente - mais j’avais choisi la distribution de référence au départ ...)

Je suis d'accord avec la réponse "ça dépend", et j'ajouterais aussi & "Dégradable gracieuse &";: le simple fait de rejeter une distribution quelque part n'est pas une raison suffisante pour laisser l'application échouer (et utilisateur perd son travail, etc.). Je recommanderais une combinaison d'assertions et de programmation défensive:

ptr = dynamic_cast<MyClass>(obj);
ASSERT(ptr);
if(ptr)
{
   // do stuff
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top