Parece que tanto static_cast como reinterpret_cast funcionan bien para convertir void * a otro tipo de puntero. ¿Hay una buena razón para favorecer a uno sobre el otro?
Parece que tanto static_cast como reinterpret_cast funcionan bien para convertir void * a otro tipo de puntero. ¿Hay una buena razón para favorecer a uno sobre el otro?
Respuestas:
Usostatic_cast
: es el modelo más estrecho que describe exactamente qué conversión se realiza aquí.
Existe la idea errónea de que usar reinterpret_cast
sería una mejor combinación porque significa "ignorar completamente la seguridad de tipo y simplemente lanzar de A a B".
Sin embargo, esto en realidad no describe el efecto de a reinterpret_cast
. Más bien, reinterpret_cast
tiene una serie de significados, para todos los cuales sostiene que "el mapeo realizado por reinterpret_cast
está definido por la implementación". [5.2.10.3]
Pero en el caso particular de echar de void*
aT*
la cartografía es completamente bien definido por la norma; a saber, asignar un tipo a un puntero sin tipo sin cambiar su dirección.
Esta es una razón para preferir static_cast
.
Además, y posiblemente más importante, es el hecho de que cada uso de reinterpret_cast
es francamente peligroso porque convierte cualquier cosa en otra cosa realmente (para punteros), mientras que static_cast
es mucho más restrictivo, proporcionando así un mejor nivel de protección. Esto ya me ha salvado de errores en los que accidentalmente intenté forzar un tipo de puntero a otro.
Esta es una pregunta difícil. Por un lado, Konrad hace un excelente comentario sobre la definición de especificaciones para reinterpret_cast , aunque en la práctica probablemente haga lo mismo. Por otro lado, si está convirtiendo entre tipos de puntero (como es bastante común al indexar en la memoria a través de un char *, por ejemplo), static_cast generará un error de compilador y se verá obligado a usar reinterpret_cast todos modos.
En la práctica, uso reinterpret_cast porque es más descriptivo de la intención de la operación de transmisión. Ciertamente, podría hacer un caso para que un operador diferente designe reinterpretaciones de puntero solamente (lo que garantiza la misma dirección devuelta), pero no hay una en el estándar.
reinterpret_cast
!
Sugiero usar siempre el molde más débil posible.
reinterpret_cast
se puede usar para lanzar un puntero a a float
. Cuanto más se rompe la estructura del elenco, más atención requiere usarlo.
En caso de char*
, usaría el molde de estilo c, hasta que tengamos algo reinterpret_pointer_cast
, porque es más débil y nada más es suficiente.
float f = *reinterpret_cast<const float*>(&p);
float
, lo cual es falso. Los moldes de expresión void **
a const float *
, y luego utiliza una operación de eliminar la referencia (que no es un elenco), para convertir const float *
a float
.
Mi preferencia personal se basa en la alfabetización de código como esta:
void* data = something;
MyClass* foo = reinterpret_cast<MyClass*>(data);
foo->bar();
o
typedef void* hMyClass; //typedef as a handle or reference
hMyClass = something;
const MyClass& foo = static_cast<MyClass&>(*hMyClass);
foo.bar();
Ambos hacen lo mismo al final, pero static_cast parece más apropiado en un entorno de aplicaciones de middleware, mientras que reinterpretar cast parece más como algo que verías en una biblioteca de nivel inferior en mi humilde opinión.