Static_cast et reinterpret_cast semblent fonctionner correctement pour la conversion de void * en un autre type de pointeur. Y a-t-il une bonne raison de privilégier l'un plutôt que l'autre?
Static_cast et reinterpret_cast semblent fonctionner correctement pour la conversion de void * en un autre type de pointeur. Y a-t-il une bonne raison de privilégier l'un plutôt que l'autre?
Réponses:
Utilisationstatic_cast
: c'est la distribution la plus étroite qui décrit exactement quelle conversion est effectuée ici.
Il y a une idée fausse selon laquelle l'utilisation reinterpret_cast
serait une meilleure correspondance, car cela signifie «ignorer complètement la sécurité de type et simplement lancer de A à B».
Cependant, cela ne décrit pas réellement l'effet d'un reinterpret_cast
. Plutôt, reinterpret_cast
a un certain nombre de significations, pour toutes qui soutient que «le mappage effectué par reinterpret_cast
est défini par l' implémentation». [5.2.10.3]
Mais dans le cas particulier de la coulée de void*
à T*
la cartographie est complètement bien défini par la norme; à savoir, pour affecter un type à un pointeur sans type sans changer son adresse.
C'est une raison de préférer static_cast
.
De plus, et sans doute plus important, est le fait que chaque utilisation de reinterpret_cast
est carrément dangereuse car elle convertit tout en n'importe quoi d'autre (pour les pointeurs), alors qu'elle static_cast
est beaucoup plus restrictive, offrant ainsi un meilleur niveau de protection. Cela m'a déjà sauvé des bogues où j'ai accidentellement essayé de forcer un type de pointeur dans un autre.
C'est une question difficile. D'une part, Konrad fait un excellent point sur la définition de spécification pour reinterpret_cast , bien qu'en pratique cela fasse probablement la même chose. D'un autre côté, si vous effectuez un cast entre des types de pointeurs (comme cela est assez courant lors de l'indexation en mémoire via un char *, par exemple), static_cast générera une erreur de compilation et vous serez de toute façon obligé d'utiliser reinterpret_cast .
En pratique, j'utilise reinterpret_cast car il est plus descriptif de l'intention de l'opération de transtypage. Vous pourriez certainement plaider en faveur d'un opérateur différent pour désigner uniquement des réinterprétations de pointeurs (qui garantissaient la même adresse renvoyée), mais il n'y en a pas dans la norme.
reinterpret_cast
!
Je suggère d'utiliser toujours le casting le plus faible possible.
reinterpret_cast
peut être utilisé pour lancer un pointeur sur a float
. Plus le plâtre est cassant la structure, plus il faut d'attention pour l'utiliser.
Dans le cas char*
contraire, j'utiliserais une fonte de style C, jusqu'à ce que nous en ayons reinterpret_pointer_cast
, car elle est plus faible et rien d'autre ne suffit.
float f = *reinterpret_cast<const float*>(&p);
float
, ce qui est faux. Les moulages d'expression void **
à const float *
, et utilise ensuite une opération de déréférencement ( ce qui est une distribution), pour convertir const float *
à float
.
Ma préférence personnelle est basée sur l'alphabétisation du code comme ceci:
void* data = something;
MyClass* foo = reinterpret_cast<MyClass*>(data);
foo->bar();
ou
typedef void* hMyClass; //typedef as a handle or reference
hMyClass = something;
const MyClass& foo = static_cast<MyClass&>(*hMyClass);
foo.bar();
Ils font tous les deux la même chose à la fin, mais static_cast semble plus approprié dans un environnement d'application intermédiaire, tandis que la réinterprétation de la distribution ressemble plus à quelque chose que vous verriez dans une bibliothèque de niveau inférieur à mon humble avis.