c++ - sirven - Forma correcta de lanzar tipos de puntero
punteros a cadenas (3)
Deberías static_cast . Utilice static_cast en los casos en que está deshaciendo una conversión implícita.
En este caso particular, sin embargo, no hay diferencia porque está convirtiendo de void* . Pero, en general, la reinterpret_cast entre dos punteros de objeto se define como (§5.2.10 / 7):
Un puntero de objeto se puede convertir explícitamente a un puntero de objeto de un tipo diferente. Cuando un prvalue
vde tipo "puntero aT1" se convierte al tipo "puntero a cvT2", el resultado esstatic_cast<cv T2*>(static_cast<cv void*>(v))si ambosT1yT2son estándar -los tipos de instalación y los requisitos de alineación deT2no son más estrictos que los deT1, o si cualquiera de los tipos esvoid. Convirtiendo un prvalue de tipo "puntero aT1" al tipo "puntero aT2" (dondeT1yT2son tipos de objetos y donde los requisitos de alineación deT2no son más estrictos que los deT1) y regresa a su tipo original, se obtiene el original valor del puntero El resultado de cualquier otra conversión de puntero no se especifica.
Énfasis mío Como T1 para ti ya está void* , el lanzamiento al void* en reinterpret_cast no hace nada. Esto no es cierto en general, que es lo que dice Drew Dormann :
#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);
}
Salida:
00CBFD5B
00CBFD5B
00CBFD5C
(Tenga en cuenta que porque y realidad no apunta a un derived , usarlo es un comportamiento indefinido).
Aquí, reinterpret_cast viene con un valor diferente porque pasa por void* . Es por eso que debes usar static_cast cuando puedas, y reinterpret_cast cuando sea necesario.
Teniendo en cuenta el siguiente código (y el hecho de que VirtualAlloc() devuelve un void* ):
BYTE* pbNext = reinterpret_cast<BYTE*>(
VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));
¿Por qué se elige reinterpret_cast lugar de static_cast ?
Yo solía pensar que reinterpret_cast está bien para, por ejemplo, lanzar punteros DWORD_PTR desde tipos enteros (como por ejemplo, DWORD_PTR ), pero para convertir de un void* a un BYTE* , ¿no static_cast bien el static_cast ?
¿Hay alguna diferencia (¿sutil?) En este caso en particular, ¿o son solo dos lanzamientos de puntero válidos?
¿El estándar C ++ tiene una preferencia para este caso, sugiriendo una forma en lugar de la otra?
El uso de static_cast para lanzar un puntero static_cast desde void* está garantizado para preservar la dirección.
reinterpret_cast por otro lado, garantiza que si se transfiere el puntero de un tipo a otro y vuelve al tipo original, la dirección se conserva.
Aunque con la mayoría de las implementaciones, vería los mismos resultados en el uso de cualquiera de estos, se preferiría static_cast .
Y con C++11 , recuerdo que usar reinterpret_cast para void* tiene un comportamiento bien definido. Antes de eso, este comportamiento estaba prohibido.
It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.
Resolución propuesta (agosto de 2010):
Cambie 5.2.10 [expr.reinterpret.cast] párrafo 7 de la siguiente manera:
Un puntero de objeto se puede convertir explícitamente a un puntero de objeto de un tipo diferente. Cuando un prvalue v de tipo "puntero a T1" se convierte al tipo "puntero a cv T2", el resultado es static_cast (static_cast (v)) si tanto T1 como T2 son tipos de disposición estándar (3.9 [basic.types] ) y los requisitos de alineación de T2 no son más estrictos que los de T1, o si cualquiera de los tipos es nulo.
Convirtiendo un prvalue 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 regresa a su tipo original, se obtiene el original valor del puntero El resultado de cualquier otra conversión de puntero no está especificado.
Más información here .
Gracias a Jesse Good por el enlace.
Para punteros a tipos fundamentales ambos moldes tienen el mismo significado; así que tienes razón de que static_cast está bien.
Al convertir entre algunos tipos de punteros, es posible que la dirección de memoria específica mantenida en el puntero necesite cambiar .
Ahí es donde los dos moldes difieren. static_cast hará el ajuste apropiado. reinterpret_cast no lo hará.
Por esa razón, es una buena regla general para static_cast entre los tipos de punteros a menos que sepa que se desea reinterpret_cast .