¿Debo usar static_cast o reinterpret_cast al emitir un vacío * a lo que sea?

Tanto static_cast como reinterpret_cast parecen funcionar bien para emitir void * a otro tipo de puntero. ¿Hay una buena razón para favorecer a uno sobre el otro?

Use static_cast : es el reparto 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 coincidencia porque significa “ignorar por completo la seguridad de tipo y simplemente enviar de A a B”.

Sin embargo, esto en realidad no describe el efecto de un reinterpret_cast . Más bien, reinterpret_cast tiene varios significados, ya que todos sostienen que “el mapeo realizado por reinterpret_cast está definido por la implementación”. [5.2.10.3]

Pero en el caso particular de conversión de void* a T* el mapeo está completamente bien definido por el estándar; a saber, para 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 algo más (para los 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 donde accidentalmente intenté forzar un tipo de puntero a otro.

Esta es una pregunta difícil. Por un lado, Konrad hace una excelente observación sobre la definición de la especificación para reinterpret_cast , aunque en la práctica probablemente haga lo mismo. Por otro lado, si está alternando entre los 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 comstackción y se verá obligado a usar reinterpret_cast de todos modos.

En la práctica, uso reinterpret_cast porque es más descriptivo de la intención de la operación de reparto. Ciertamente se podría hacer un caso para que un operador diferente designe únicamente reinterpretadores de punteros (lo que garantiza que se devuelva la misma dirección), pero no hay ninguno en el estándar.

Sugiero usar el molde más débil posible siempre.

reinterpret_cast se puede usar para lanzar un puntero a un float . Cuanto más rompe la estructura del elenco, más requiere su uso de la atención.

En el caso de char* , usaría elenco c-style, hasta que tengamos reinterpret_pointer_cast , porque es más débil y nada más es suficiente.

Mi preferencia personal se basa en la alfabetización de código de esta manera:

 void* data = something; MyClass* foo = reinterpret_cast(data); foo->bar(); 

o

 typedef void* hMyClass; //typedef as a handle or reference hMyClass = something; const MyClass& foo = static_cast(*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 el reinterpretcast parece más como algo que verías en una biblioteca de nivel inferior en mi humilde opinión.