241 votes

Dois-je utiliser static_cast ou reinterpret_cast pour couler un void* vers n'importe quel type d'objet ?

Les deux sites static_cast y reinterpret_cast semblent bien fonctionner pour le moulage void* à un autre type de pointeur. Y a-t-il une bonne raison de privilégier l'un plutôt que l'autre ?

79 votes

@anon Apparemment, vous n'avez jamais travaillé avec des threads POSIX.

8 votes

@user470379 Wow... c'est la raison même pour laquelle j'ai atterri sur cette question à SO ! Excellente observation :-).

191voto

Konrad Rudolph Points 231505

Utilisez static_cast il s'agit de la distribution la plus étroite qui décrit exactement ce que la conversion est faite ici.

Il y a une idée fausse selon laquelle utiliser reinterpret_cast correspondrait mieux, car il signifie "ignorer complètement la sécurité des types et lancer simplement de A à B".

Cependant, cela ne décrit pas réellement l'effet d'une reinterpret_cast . Plutôt, reinterpret_cast a un certain nombre de significations, pour lesquelles on considère que "la mise en correspondance effectuée par reinterpret_cast est définie par la mise en œuvre." [5.2.10.3]

Mais dans le cas particulier de la coulée de void* a T* le mappage est complètement bien défini par la norme ; à savoir, attribuer un type à un pointeur sans type sans changer son adresse.

C'est une raison de préférer static_cast .

En outre, et c'est sans doute le plus important, chaque utilisation de l'outil reinterpret_cast est carrément dangereux car il convertit n'importe quoi en n'importe quoi d'autre (pour les pointeurs), alors que static_cast est beaucoup plus restrictive, offrant ainsi un meilleur niveau de protection. Cela m'a déjà sauvé de bogues où j'ai accidentellement essayé de forcer un type de pointeur dans un autre.

59voto

Vous devez no utiliser reinterpret_cast . Le transfert d'un pointeur de void* n'est pas autorisé en utilisant reinterpret_cast (5.2.10/7 depuis void n'est pas un type d'objet. IMHO c'est une façon valide de le lire, même si certains compilateurs ne le diagnostiquent pas). reinterpret_cast peut être utilisé pour effectuer un cast entre certains types de pointeurs non liés lors de l'écriture de code dépendant de la plateforme, si nécessaire.

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

Lorsque vous voulez faire un casting à partir de void* à quelque chose d'autre, vous pouvez utiliser static_cast . La norme l'autorise explicitement. La conversion d'un type en un autre type (différent) à l'aide de la fonction void* entre les deux cédera à une valeur de pointeur non spécifiée. Cependant, parfois, lorsque vous devez écrire du code dépendant de la plate-forme, cela ne peut être évité.

Une rvalue de type "pointeur vers cv void" peut être explicitement convertie en un pointeur vers un type objet. Une valeur de type pointeur d'objet convertie en "pointeur de cv void" et de nouveau en pointeur de type original aura sa valeur originale.


Mise à jour : Le comité va permettre reinterpret_cast<> de et vers void* pour C++0x. Voir Numéro 1120 .

12voto

Nick Points 5293

C'est une question difficile. D'une part, Konrad soulève un excellent point concernant la définition de la spécification de l'expression réinterpréter_cast bien qu'en pratique, il fasse probablement la même chose. D'un autre côté, si vous effectuez un casting entre des types de pointeurs (ce qui 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 obligé d'utiliser réinterpréter_cast de toute façon.

En pratique, j'utilise réinterpréter_cast parce que c'est plus descriptif de l'intention de l'opération de cast. Vous pourriez certainement défendre l'idée d'un opérateur différent pour désigner les réinterprétations de pointeurs uniquement (qui garantissent le retour de la même adresse), mais il n'y en a pas dans la norme.

8 votes

" opérateur différent pour désigner le pointeur réinterprète seulement (qui garantissait la même adresse retournée) " Câlin ? Cet opérateur es reinterpret_cast !

4 votes

@curiousguy Pas vrai selon la norme. reinterpret_cast ne garantit PAS que la même adresse est utilisée. Seulement que si vous réinterprétez_cast d'un type à l'autre et puis de nouveau vous retrouverez la même adresse qu'au départ.

0voto

Pavel Radzivilovsky Points 11613

Je suggère de toujours utiliser la distribution la plus faible possible.

reinterpret_cast peut être utilisé pour convertir un pointeur vers un fichier float . Plus le plâtre brise la structure, plus il nécessite une attention particulière.

En cas de char* j'utiliserais le cast de style c, jusqu'à ce que nous ayons une certaine reinterpret_pointer_cast parce qu'il est plus faible et que rien d'autre n'est suffisant.

3 votes

" reinterpret_cast peut être utilisé pour convertir un pointeur en un flottant. " Certainement pas !

0 votes

Certainement oui, curieuxguy. Vérifiez à nouveau la norme.

0 votes

" Vérifiez à nouveau la norme. " Avoir vous a vérifié la norme ?

-9voto

Robert Gould Points 29406

Ma préférence personnelle se fonde sur une connaissance du code comme celui-ci :

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();

Les deux font la même chose au final, mais static_cast semble plus approprié dans un environnement de middle-ware, d'application, alors que reinterpret cast semble plus être quelque chose que vous verriez dans une bibliothèque de niveau inférieur IMHO.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X