Forma adecuada de tipos de puntero de fundición
Considerando el siguiente código (y el hecho de que VirtualAlloc()
devuelve a void*
):
BYTE* pbNext = reinterpret_cast<BYTE*>(
VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));
¿Por qué se elige reinterpret_cast
en lugar de static_cast
?
Solía pensar que reinterpret_cast
está bien para, por ejemplo, lanzar punteros hacia y desde tipos enteros (como, por ejemplo, DWORD_PTR
), pero para lanzar desde un void*
a un BYTE*
, no está bien static_cast
?
¿Hay alguna (sutil?) las diferencias en este caso en particular, o son solo los dos moldes de puntero válidos?
¿El estándar C++ tiene un preferencia por este caso, sugiriendo una forma en lugar de la otra?
3 answers
Para punteros a tipos fundamentales ambos moldes tienen el mismo significado; por lo que está en lo correcto que static_cast
está bien.
Al convertir entre algunos tipos de puntero, 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 tipos de puntero a menos que sepa que reinterpret_cast
se desea.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-30 15:21:44
Deberías static_cast
. Use 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ás convirtiendo desde void*
. Pero en general, reinterpret_cast
ing entre dos punteros de objeto se define como (§5.2.10/7):
Un puntero de objeto se puede convertir explícitamente en un puntero de objeto de un tipo diferente. Cuando un prvalue
v
de tipo "puntero aT1
" se convierte en el tipo " puntero a cvT2
", el resultado esstatic_cast<cv T2*>(static_cast<cv void*>(v))
si tantoT1
comoT2
son tipos de disposición estándar y los requisitos de alineación deT2
no son más estrictos que los deT1
, o si cualquiera de los tipos esvoid
. Convertir un prvalue de tipo " puntero aT1
" al tipo "puntero aT2
" (dondeT1
yT2
son tipos de objeto y donde los requisitos de alineación deT2
no son más estrictos que los deT1
) y volver a su tipo original produce el valor del puntero original. El resultado de cualquier otro puntero la conversión no está especificada.
Énfasis mío. Puesto que T1
para ti ya es void*
, el reparto a void*
en reinterpret_cast
no hace nada. Esto no es cierto en general, que es lo que Drew Dormann está diciendo :
#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 debido a que y
no apunta realmente 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 tengas que hacerlo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:04
Usar static_cast
para lanzar un puntero hacia y desde void*
está garantizado para preservar la dirección.
reinterpret_cast
por otro lado, garantiza que si envía el puntero de un tipo a otro, y de vuelta al tipo original, la dirección se conserva.
Aunque con la mayoría de las implementaciones, verá los mismos resultados al usar cualquiera de estas, static_cast
debe ser preferido.
Y con C++11
recuerdo que usar reinterpret_cast
para void*
tiene un comportamiento bien definido. Antes de que esto el comportamiento estaba prohibido.
It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.
Propuesta de resolución (agosto de 2010):
Change 5.2.10 [expr.reinterpretar.cast] paragraph 7 as follows:
Un puntero de objeto se puede convertir explícitamente en un puntero de objeto de un tipo diferente. Cuando un prvalue v de tipo "puntero a T1" es convertido al tipo "puntero a cv T2", el resultado es static_cast(static_cast (v)) si tanto T1 como T2 son de diseño estándar tipos (3.9 [básico.tipos]) y la alineación los requisitos de T2 no son más estrictas que las de T1, o si cualquiera de los tipos es nulo.
Convirtiendo un prvalue del tipo "puntero a T1" al tipo " puntero a T2 " (donde T1 y T2 son tipos de objetos y donde la alineación requisitos de T2 no son más estrictos que los de T1) y volver a su el tipo original produce el valor del puntero original. El resultado de cualquier otra conversión de puntero no está especificada.
Más información aquí.
Gracias a Jesse Bueno para el enlace.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:55