2008-11-21 13 views
144

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?Debo usar static_cast o reinterpret_cast al emitir un vacío * a lo que sea

+3

Una mejor pregunta sería "¿Cómo evito usar punteros vacíos en mi código?". Esto no es difícil de hacer, no recuerdo la última vez que usé uno. –

+60

@anon Aparentemente nunca antes has trabajado con hilos POSIX. – user470379

+3

@ user470379 Wow ... esa es la razón por la que llegué a esta pregunta en SO! Excelente observación :-). –

Respuesta

88

Use static_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 coincidencia porque significa "ignorar por completo la seguridad de tipo y simplemente enviar de A a B". Sin embargo, esto no describe el efecto de reinterpret_cast. Más bien, reinterpret_cast tiene una serie de significados, para todos los cuales sostiene que “la asignación realizada por reinterpret_cast es definido por la implementación.” [5.2.10.3]

Pero en el caso particular de fundición de void* a T* el mapeo es 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 muy peligroso ya que convierte cualquier cosa a cualquier otra cosa realmente (para los punteros), mientras que static_cast es mucho más restrictiva, lo que proporciona un mayor nivel de protección. Esto ya me ha salvado de errores donde accidentalmente intenté forzar un tipo de puntero a otro.

5

Esta es una pregunta difícil. Por un lado, Konrad hace una excelente observación sobre la definición de la especificación reinterpret_cast, aunque en la práctica probablemente haga lo mismo. Por otro lado, si está alternando entre tipos de punteros (como es bastante común al indexar en la memoria a través de un char *, por ejemplo), static_cast generará un error de compilación y se le forzará a usar reinterpret_cast de todas formas.

En la práctica uso reinterpret_cast porque es más descriptivo de la intención de la operación de conversión. 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.

+6

"_diferente operador para designar puntero reinterpreta solamente (lo que garantiza la misma dirección devuelta) _" ¿Abrazo? Ese operador ** es ** 'reinterpret_cast'! – curiousguy

-2

Mi preferencia personal se basa en la alfabetización código como este:

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 en el final, pero static_cast parece más apropiado en un medio-ware, entorno de la aplicación, mientras que reinterpretar el elenco parece más como algo que verías en una biblioteca de nivel inferior en mi humilde opinión.

+4

El segundo ejemplo de código no se compilará. –

2

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

reinterpret_cast se puede utilizar para lanzar un puntero a un flotador. Cuanto más elemental es el reparto de estructuras, más atención requiere su uso.

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

+0

"_reinterpret_cast se puede usar para lanzar un puntero a un float._" Ciertamente no! – curiousguy

+0

ciertamente sí, curiousguy. Verifique el estándar nuevamente. –

+0

¿Puedes dar un ejemplo? – curiousguy

Cuestiones relacionadas