2011-12-18 10 views
5

segun la normativa aliasing estrictas:char * de conversión y las reglas de alias

struct B { virtual ~B() {} }; 
struct D : public B { }; 

D d; 
char *c = reinterpret_cast<char*>(&d); 

A char* a cualquier objeto de diferente tipo es válido. Pero ahora la pregunta es, ¿apuntará a la misma dirección de & d? ¿Cuál es la garantía hecha por C++ Standard de que devolverá la misma dirección?

+9

Creo que su destructor está mal llamado –

+4

No sé la respuesta. Pero, ¿cuándo sería este conocimiento ** alguna vez útil en la práctica? –

+0

Buena pregunta. Algunos moldes realmente pueden cambiar la dirección (por ejemplo, cuando se trata de herencia múltiple).Me pregunto si ese es el caso. – Kos

Respuesta

6

c&d y efectivamente tienen el mismo valor, y si reinterpretar-Cast c de nuevo a un D* se obtiene un puntero válido que puede eliminar la referencia. Además, puede tratar c como (puntero al primer elemento de) una matriz opaca char[sizeof(D)] - este es de hecho el propósito principal de lanzar punteros a punteros char: Para permitir (de) serialización (p. Ej. ofile.write(c, sizeof(D));), aunque en general solo debería haga esto para los tipos primitivos (y arreglos de los mismos), ya que la disposición binaria de los tipos compuestos generalmente no se especifica de manera portátil.

Como señala correctamente @Oli y me gustaría que lo reforzase, en realidad nunca debería serializar los tipos de compuestos como un todo. El resultado casi nunca será deserializable, ya que la implementación de clases polimórficas y el relleno entre los campos de datos no está especificada y no es accesible para usted.

Tenga en cuenta que reinterpret_cast<char*>(static_cast<B*>(&d)) se puede tratar como una matriz opaca char[sizeof(B)] por un razonamiento similar.

+0

Creo que quizás deba aclarar que la serialización/deserialización de clases que no son POD como esta (es decir, las que tienen vptrs) es una muy mala idea. –

+0

@OliCharlesworth: Hm, los * objetos * no tienen ningún "vptrs" oculto ... eso es todo solo en la implementación de la clase. Los objetos aún deberían tener un diseño bastante "normal", al menos hasta que ingrese a la herencia virtual ... los problemas de relleno habituales son una razón mucho más inmediata para no serializar los tipos de clase de forma "ingenua" (aunque, de nuevo, puede haber situaciones en las que está bien, por ejemplo, agrupaciones HPC de máquinas idénticas que utilizan E/S de red mapeada en memoria ...). Comprador tenga cuidado :-) –

+0

¿Qué? La existencia de funciones virtuales significa que las instancias de clase deben tener un vptr (bueno, en cualquier implementación típica). –

2

Sección 5.2.10, punto 7 de la C++ Standard 2003 dice:

Un puntero a un objeto se puede convertir explícitamente a un puntero a un objeto de diferente tipo. Excepto que la conversión de un valor de tipo "puntero a T1" al tipo "puntero a T2" (donde T1 y T2 son tipos de objetos y donde los requisitos de alineación de T2 no son más estrictos que los de T1) y volver a su tipo original produce el valor del puntero original, el resultado de dicha conversión de puntero es no especificado.

Si con "misma dirección" quiere decir "valor de puntero original", esta entrada dice "sí".

0

La intención es clara (y no es algo que necesita ser discutido):

reinterpret_cast nunca cambia el valor de una dirección, a menos que el tipo de destino no puede representar todos los valores de dirección (como un pequeño tipo entero, en un tipo de puntero con alineación intrínseca: por ejemplo, un puntero que solo puede representar direcciones pares, o punteros a objetos y punteros a funciones no pueden mezclarse ...).

La redacción de la norma no logra capturar eso, pero eso no significa que haya un problema práctico real aquí.

char *c = reinterpret_cast<char*>(&d); 

c apuntará al primer byte de d, siempre.

Cuestiones relacionadas