Pregunta

¿Existe alguna buena práctica relacionada con el manejo de errores de Dynamic_cast (excepto no usarlo cuando no es necesario)?Me pregunto cómo debo hacer con NULL y bad_cast que puede generar.¿Debería comprobar ambos?Y si detecto bad_cast o detecto NULL, probablemente no pueda recuperarme de todos modos...Por ahora, estoy usando afirmar para verificar si Dynamic_cast no devolvió un valor NULL.¿Aceptaría esta solución en una revisión de código?

¿Fue útil?

Solución

Si el dynamic_cast debería tener éxito, sería una buena práctica utilizar boost::polymorphic_downcast en cambio, que es más o menos así:

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

De esta manera, detectará errores en la compilación de depuración y, al mismo tiempo, evitará la sobrecarga del tiempo de ejecución en una compilación de lanzamiento.

Si sospechas del elenco podría falla y quieres detectarlo, usa dynamic_cast y convertir a un tipo de referencia.Este elenco arrojará bad_cast en caso de error, y eliminará su programa.(Esto es bueno si, como dices, de todos modos no te vas a recuperar)

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

Usar dynamic_cast a un tipo de puntero solo si el puntero 0 tiene sentido en el contexto.Es posible que desee utilizarlo en un if como esto:

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

Con esta última opción, debe asegurarse de que la ruta de ejecución tenga sentido si el dynamic_cast devuelve 0.

Para responder a su pregunta directamente:Preferiría que una de las dos primeras alternativas que he dado fuera tener una declaración explícita assert en el código :)

Otros consejos

bad_cast solo se lanza al transmitir referencias

dynamic_cast< Derived & >(baseclass)

NULL se devuelve al lanzar punteros

dynamic_cast< Derived * >(&baseclass)

Así que nunca hay necesidad de verificar ambos.

La afirmación puede ser aceptable, pero eso depende en gran medida del contexto, una vez más, eso es cierto para casi todas las afirmaciones ...

Sí y no.

boost::polymorphic_downcast<> es seguramente una buena opción para manejar errores de dynamic_cast<> durante la fase de depuración. Sin embargo, vale la pena mencionar que polymorphic_downcast<> debe usarse solo cuando es posible predecir el tipo polimórfico pasado en tiempo de compilación , de lo contrario, <=> debe usarse en su lugar.

Sin embargo, una secuencia de:

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

denota un diseño muy malo que debe resolverse mediante polimorfismo y funciones virtuales .

Depende ... ;-)

Si realmente esperaba que el dynamic_cast me diera algo utilizable, por ejemplo, si yo y nadie más agregamos un tipo polimórfico a un contenedor de punteros a una clase base, entonces iría con el modelo de referencia y dejaría que std::bad_cast matar mi aplicación; en realidad, no habría mucho más que hacer.

Sin embargo, si estoy consultando un tipo polimórfico para alguna capacidad expuesta por una interfaz que no necesariamente tiene que implementar, entonces iría con el puntero y luego un NULL no sería un error ( a menos que, por supuesto, esperara la capacidad de realmente estar allí, pero en primer lugar había elegido el elenco de referencia ...)

Coincidiría con la respuesta 'depende', y también agregaría " Degradación elegante " ;: solo porque una conversión falla en alguna parte no es razón suficiente para dejar que la aplicación falle (y el el usuario pierde su trabajo, etc.). Recomiendo una combinación de afirmaciones y programación defensiva:

ptr = dynamic_cast<MyClass>(obj);
ASSERT(ptr);
if(ptr)
{
   // do stuff
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top