c++ - seguridad - maquina para quitar seguros de ropa
¿Dynamic_casts es seguro para eliminar en el código de producción? (5)
dynamic_cast
s son más lentos, pero son más seguros que static_cast
s (cuando se usan con jerarquías de objetos, por supuesto). Mi pregunta es, después de haber asegurado en mi código de depuración que todos los moldes (dinámicos) son correctos, ¿hay alguna razón para que no los cambie a static_cast
s?
Planeo hacer esto con la siguiente construcción. (Por cierto, ¿se te ocurre un nombre mejor que assert_cast
? ¿Tal vez debug_cast
?)
#if defined(NDEBUG)
template<typename T, typename U>
T assert_cast(U other) {
return static_cast<T>(other);
}
#else
template<typename T, typename U>
T assert_cast(U other) {
return dynamic_cast<T>(other);
}
#endif
Editar: Boost ya tiene algo para esto: polymorphic_downcast
. Gracias a PlasmaHH por señalar eso.
después de haber asegurado en mi código de depuración que todos los moldes (dinámicos) son correctos, ¿hay alguna razón para que no los cambie a static_casts?
En mi humilde opinión, si está 100% seguro de que todos los dynamic_cast<>
son correctos, entonces no hay razón para no cambiarlos a static_cast<>
. Puedes cambiarlos
¡No! dynamic_cast
hace más que simplemente lanzar. Puede verificar el tipo de tiempo de ejecución del objeto. Pero también puede atravesar jerarquías desconocidas para el compilador, pero solo se conocen en tiempo de ejecución. static_cast
no puede hacer eso.
Por ejemplo:
class A1
{
virtual ~A1() {}
};
class A2
{
virtual ~A2() {}
};
class B : public A1, public A2
{ };
A1 *a1 = new B;
A2 *a2 = dynamic_cast<A2*>(a1); //no static_cast!
A1 *x = ...;
if (B *b = dynamic_cast<B*>(x)) //no static_cast!
/*...*/;
Debe afirmar que dynamic_cast
tuvo éxito:
template<typename T, typename U>
T *assert_cast(U *other) {
T *t = dynamic_cast<T>(other);
assert(t);
return t;
}
Reemplazar dynamic_cast
con static_cast
en una situación en la que esté seguro de que son equivalentes es lo mismo que eliminar las comprobaciones nulas para el puntero que está seguro es siempre no nulo. Puedes hacerlo por motivos de rendimiento.
Siempre y cuando haya probado con todas las combinaciones posibles de factores de tiempo de ejecución / variables / entradas, seguro. Como se mencionó en los comentarios, esto sería similar a eliminar aseveraciones.
No hay nada en el lenguaje que lo haga inherentemente inseguro, teniendo en cuenta las garantías necesarias de que tus lanzamientos siempre serán correctos. Sin embargo, se siente intrínsecamente inseguro, en el sentido de que probablemente nunca podría hacer esa garantía.
Actualizar
Konstantin ha demostrado que, cuando se trata de herencia múltiple, esta técnica solo funcionará para pasos únicos arriba / abajo del árbol de herencia 1 .
struct A1 { virtual ~A1() {} };
struct A2 { virtual ~A2() {} };
struct A3 { virtual ~A3() {} };
struct B : A1, A2 {};
struct C : A1, A3, A2 {};
int main() {
A1* a1 = (rand() < RAND_MAX / 2 ? (A1*)new B : (A1*)new C);
A2* p1 = dynamic_cast<A2*>(a1);
// ^ succeeds, but is a cross-cast
// A2* p2 = static_cast<A2*>(a1);
// ^ ill-formed
A2* p3 = static_cast<A2*>(static_cast<B*>(a1));
// ^ must chain, instead.
// but p3 is invalid because we never
// checked that `dynamic_cast<B*>(a1)` is valid.. and it''s not
// Instead, let''s expand the `dynamic_cast`s into a chain, too:
A2* p3 = dynamic_cast<B*>(a1);
A2* p4 = dynamic_cast<A2>*(a1);
// ^ p3 fails, so we know that we cannot use `static_cast` here
}
Por lo tanto, puede reemplazar su dynamic_cast
s con static_cast
s iff:
- Cada
dynamic_cast
realiza solo un paso hacia arriba o hacia abajo; - Se sabe que cada
dynamic_cast
siempre tiene éxito.
1 En realidad, esto es una simplificación, ya que, por ejemplo, los downcasts funcionarán para cualquier cantidad de pasos. Pero es una buena regla empírica.
Supongo que depende del proyecto. Si se trata de un software de gestión de central nuclear, preferiría seguridad, si es un juego 3D, preferiría el rendimiento. Nunca puede estar seguro de que todo el dynamic_cast
será correcto en el código de producción. Si el rendimiento es más importante que la seguridad, elimine.