Pregunta

Necesito convertir un tipo entero que contiene una dirección al tipo de puntero real. Podría usar reinterpret_cast de la siguiente manera:

MyClass *mc1 = reinterpret_cast<MyClass*>(the_integer);

Sin embargo, esto no realiza ninguna comprobación en tiempo de ejecución para ver si la dirección en cuestión en realidad contiene un objeto MiClase. Quiero saber si hay algún beneficio en la primera conversión a un void * (usando reinterpret_cast) y luego usando dynamic_cast en el resultado. De esta manera:

void *p = reinterpret_cast<void*>(the_integer);
MyClass *mc1 = dynamic_cast<MyClass*>(p);
assert(mc1 != NULL);

¿Hay alguna ventaja en el uso del segundo método?

¿Fue útil?

Solución

La verificación de tipos en dynamic_cast está implementado de diferentes maneras por diferentes implementaciones de C ++; si desea una respuesta para su aplicación específica debe mencionar lo que la aplicación que esté utilizando. La única manera de responder a la pregunta en general es referirse a ISO ++ C estándar.

Por mi lectura de la norma, llamando dynamic_cast en un puntero nulo es ilegal:

dynamic_cast<T>(v)
  

"Si T es un tipo de puntero, v será un valor p de un puntero para completar tipo de clase"

(de 5.2.7.2 de la norma de la ISO C ++). void no es un tipo de clase completa, por lo que la expresión es ilegal.

Curiosamente, el tipo que era echado a se le permite ser un puntero nulo, es decir.

void * foo = dynamic_cast<void *>(some_pointer);

En este caso, la dynamic_cast siempre tiene éxito, y el valor resultante es un puntero al objeto más derivada apuntado por v.

Otros consejos

No, no hay ninguna ventaja específica en hacerlo. En el momento en que utilice reinterpret_cast, todas las apuestas están apagadas. Es hasta usted para asegurarse de que el reparto es válido.

En realidad ninguna ventaja seria. Si el vacío * puntos a algo que no es un puntero a un objeto polimórfico se encuentra con un comportamiento indefinido (por lo general una violación de acceso) inmediatamente.

La forma más segura es mantener un registro de todos los objetos MiClase vivo. Lo mejor es mantener este registro en una std::set<void*>, lo que significa que puede fácilmente añadir, quitar y elementos de prueba.

La razón de su almacenamiento como void*s es que no corre el riesgo nastyness como la creación de punteros MyClass* no alineados de los números enteros.

  • En primer lugar "reinterpretación" int a void * es una mala idea. Si sizeof(int) es 4 y sizeof(void *) es 8 (64x del sistema) que está mal formada.

  • dynamic_cast

    Además es válido sólo para el caso de las clases polimórficas.

La opción 1 es la única (semi) portátil opción / válido.

Opción 2: no es válido C ++ como el dynamic_cast (como no se permite void)

.

A nivel aplicación que requiere escribir información desde el tipo de fuente para llegar al tipo de destino. No hay manera (o puede haber ninguna manera) para obtener la información de tipo de fuente de tiempo de ejecución de un void * así que esto no es válido tampoco.

dynamic_cast se utiliza a CAS arriba y abajo de la jerarquía de tipo no de tipos desconocidos.

Como un lado, tenga en cuenta que probablemente debería utilizar void * en vez de un entero para almacenar un puntero sin tipo. Hay potencial para un int no sea lo suficientemente grande como para almacenar un puntero.

La forma más segura de manejar punteros en C ++ es para manejarlos typesafe. Esto significa:

  • Nunca almacenan punteros en otra cosa que un puntero
  • Evite los punteros void
  • Nunca pasar punteros a otros procesos
  • weak_ptr considerar si va a utilizar punteros sobre las roscas

La razón de esto es: lo que usted está planeando hacer no es seguro y puede ser evitado a menos que estés interfaz con código no seguro (legado?). En este caso tener en cuenta la respuesta MSalters', pero tenga en cuenta que todavía es una molestia.

Si sabe con certeza que the_integer apunta a una clase base (conocida que tiene al menos un miembro virtual), no podrían de hecho ser una ventaja: sabiendo que el objeto es de una clase derivada específica. Pero habría que reinterpret_cast a su clase base primero y luego hacer la dynamic_cast:

BaseClass* obj = reinterpret_cast<BaseClass*>(the_integer);
MyClass* myObj = dynamic_cast<BaseClass*>(obj);

El uso de un void* en dynamic_cast es inútil y simplemente errónea. No se puede utilizar dynamic_cast para comprobar si hay un objeto válido en alguna ubicación arbitraria en la memoria.

También se debe prestar atención al almacenar las direcciones de las variables de tipo no-puntero. Hay arquitecturas donde sizeof (void *)! = Sizeof (int), por ejemplo, LP64.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top