Considérant le code suivant (et le fait que VirtualAlloc()
renvoie un void*
):
BYTE* pbNext = reinterpret_cast<BYTE*>(
VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));
pourquoi est-ce reinterpret_cast
choisi au lieu de static_cast
?
Je pensais que reinterpret_cast
est OK pour par exemple caster des pointeurs vers et à partir de types entiers (comme par exemple DWORD_PTR
), mais pour lancer à partir d'un void*
à un BYTE*
, n'est-ce pas static_cast
D'ACCORD?
Existe-t-il des différences (subtiles?) Dans ce cas particulier, ou s'agit-il simplement de deux lancers de pointeurs valides?
La norme C++ a-t-elle une préférence pour ce cas, suggérant une voie au lieu de l'autre?
Pour pointeurs convertibles en types fondamentaux les deux transtypages ont la même signification; vous avez donc raison que static_cast
est correct.
Lors de la conversion entre certains types de pointeurs, il est possible que l'adresse mémoire spécifique contenue dans le pointeur doive changer .
C'est là que les deux modèles diffèrent. static_cast
fera le réglage approprié. reinterpret_cast
ne le sera pas.
Pour cette raison, c'est une bonne règle générale de static_cast
entre les types de pointeurs, sauf si vous savez que reinterpret_cast
est désiré.
Vous devez static_cast
. Utilisez static_cast
Dans les cas où vous annulez une conversion implicite.
Dans ce cas particulier, cependant, il n'y a pas de différence car vous effectuez une conversion à partir de void*
. Mais en général, reinterpret_cast
Entre deux pointeurs d'objet est défini comme étant (§5.2.10/7):
Un pointeur d'objet peut être explicitement converti en un pointeur d'objet d'un type différent. Lorsqu'une valeur
v
de type "pointeur versT1
" Est convertie en type "pointeur vers cvT2
", le résultat eststatic_cast<cv T2*>(static_cast<cv void*>(v))
siT1
etT2
sont tous deux des types de mise en page standard et que les exigences d'alignement deT2
ne sont pas plus strictes que ceux deT1
, ou si l'un ou l'autre type estvoid
. Conversion d'une valeur de type "pointeur versT1
" En type "pointeur versT2
" (OùT1
EtT2
Sont des types d'objets et où l'alignement les exigences deT2
ne sont pas plus strictes que celles deT1
) et revenir à son type d'origine donne la valeur du pointeur d'origine. Le résultat de toute autre conversion de pointeur de ce type n'est pas précisé.
Je souligne. Étant donné que T1
Pour vous est déjà void*
, La conversion vers void*
Dans reinterpret_cast
Ne fait rien. Ce n'est pas vrai en général, c'est ce que Drew Dormann dit :
#include <iostream>
template <typename T>
void print_pointer(const volatile T* ptr)
{
// this is needed by oversight in the standard
std::cout << static_cast<void*>(const_cast<T*>(ptr)) << std::endl;
}
struct base_a {};
struct base_b {};
struct derived : base_a, base_b {};
int main()
{
derived d;
base_b* b = &d; // implicit cast
// undo implicit cast with static_cast
derived* x = static_cast<derived*>(b);
// reinterpret the value with reinterpret_cast
derived* y = reinterpret_cast<derived*>(b);
print_pointer(&d);
print_pointer(x);
print_pointer(y);
}
Sortie:
00CBFD5B
00CBFD5B
00CBFD5C
(Notez que parce que y
ne pointe pas réellement vers un derived
, son utilisation est un comportement non défini.)
Ici, reinterpret_cast
Propose une valeur différente car elle passe par void*
. C'est pourquoi vous devez utiliser static_cast
Quand vous le pouvez et reinterpret_cast
Quand vous le devez.
En utilisant static_cast
pour placer un pointeur vers et depuis void*
est garanti pour conserver l'adresse.
reinterpret_cast
d'autre part garantit que si vous convertissez le pointeur d'un type en un autre et que vous revenez au type d'origine, l'adresse est conservée.
Bien qu'avec la plupart des implémentations, vous obtiendrez les mêmes résultats en utilisant l'un de ces éléments, static_cast
devrait être préféré.
Et avec C++11
Je m'en souviens, en utilisant reinterpret_cast
pour void*
a un comportement bien défini. Avant cela, ce comportement était interdit.
It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.
Proposition de résolution (août 2010):
Modifier le paragraphe 7 de 5.2.10 [expr.reinterpret.cast] comme suit:
Un pointeur d'objet peut être explicitement converti en un pointeur d'objet d'un type différent. Lorsqu'une valeur pr de type "pointeur vers T1" est convertie en type "pointeur vers cv T2", le résultat est static_cast (static_cast (v)) si T1 et T2 sont tous deux de type standard (3.9 [basic.types]) et que les exigences d'alignement de T2 ne sont pas plus strictes que celles de T1, ou si l'un ou l'autre type est nul.
La conversion d'une valeur de type "pointeur vers T1" en type "pointeur vers T2" (où T1 et T2 sont des types d'objet et où les exigences d'alignement de T2 ne sont pas plus strictes que celles de T1) et de retour à son type d'origine donne l'original valeur du pointeur. Le résultat de toute autre conversion de pointeur de ce type n'est pas spécifié.
Plus d'infos ici .
Merci à Jesse Good pour le lien.