2011-12-18 7 views
5

Selon les règles strictes d'aliasing:char * conversion et règles aliasing

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

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

A char* à tout objet de type différent est valide. Mais maintenant la question est, pointera-t-elle à la même adresse de & d? quelle est la garantie faite par C++ Standard qu'il retournera la même adresse?

+9

Je pense que votre destructeur est mal nommé –

+4

Je ne connais pas la réponse. Mais, quand cette connaissance serait-elle jamais utile dans la pratique? –

+0

Bonne question. Certaines conversions peuvent en fait changer l'adresse (par exemple lorsque l'héritage multiple est impliqué).Je me demande si c'est le cas. – Kos

Répondre

6

c et &d ont en effet la même valeur, et si vous c réinterprétez-rejetterait à un D* vous obtenez un pointeur valide que vous pouvez déréférencer. En outre, vous pouvez traiter c comme (pointeur vers le premier élément de) un tableau opaque char[sizeof(D)] - c'est en effet le but principal de la diffusion de pointeurs vers des pointeurs char: Pour autoriser la (dé) sérialisation (par exemple ofile.write(c, sizeof(D));), bien que vous ne devriez généralement faites ceci pour les types primitifs (et leurs tableaux), puisque la disposition binaire des types composés n'est généralement pas spécifiée de manière portable. Comme @Oli le souligne à juste titre et voudrait que je le renforce, vous ne devriez jamais sérialiser les types composés dans leur ensemble. Le résultat ne sera presque jamais désérialisable, puisque l'implémentation de classes polymorphes et le remplissage entre les champs de données ne sont pas spécifiés et ne sont pas accessibles pour vous.

Notez que reinterpret_cast<char*>(static_cast<B*>(&d)) peut être traité comme un tableau opaque char[sizeof(B)] par un raisonnement similaire.

+0

Je pense que vous devriez peut-être clarifier que sérialiser/désérialiser des classes non-POD comme celle-ci (c'est-à-dire celles avec vptrs) est une très très mauvaise idée. –

+0

@OliCharlesworth: Hm, les * objets * n'ont pas de "vptrs" cachés ... tout est juste dans l'implémentation de la classe. Les objets doivent toujours avoir une disposition assez "normale", au moins jusqu'à ce que vous entriez dans l'héritage virtuel ... les problèmes de remplissage habituels sont une raison beaucoup plus immédiate de ne pas sérialiser les types de classe de manière "naïve" (bien que les situations où c'est OK, par exemple les clusters HPC de machines identiques utilisant des E/S réseau mappées en mémoire ...). Acheteur méfiez-vous :-) –

+0

Quoi? L'existence de fonctions virtuelles signifie que les instances de classe doivent avoir un vptr (bien, dans toute implémentation typique). –

2

section 5.2.10, point 7 de 2003 C++ standard dit:

Un pointeur sur un objet peut être explicitement converti en un pointeur vers un objet de type différent. Sauf que convertir un rvalue de type "pointeur en T1" en type "pointeur en T2" (où T1 et T2 sont types d'objet et où les exigences d'alignement de T2 ne sont pas plus strictes que celles de T1) et retour à son type d'origine donne la valeur du pointeur d'origine, le résultat d'une telle conversion est non spécifié.

Si par "même adresse" vous entendez "valeur du pointeur d'origine", cette entrée indique "oui".

0

L'intention est claire (et non quelque chose qui doit être débattue):

reinterpret_cast ne change jamais la valeur d'une adresse, à moins que le type de cible ne peut pas représenter toutes les valeurs d'adresse (comme un petit type entier, sur un type de pointeur avec alignement intrinsèque: f.ex. un pointeur qui ne peut représenter que des adresses paires, ou des pointeurs vers des objets et des pointeurs vers des fonctions ne peuvent pas être mélangés ...).

Le libellé de la norme ne parvient pas à capturer cela, mais cela ne signifie pas qu'il existe un réel problème pratique ici.

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

c pointera vers le premier octet de d, toujours.