Dado el código
struct A {};
auto obj = new A;
std::vector<unsigned char> buffer;
buffer.resize(sizeof(obj));
std::memcpy(buffer.data(), &obj, sizeof(obj)); // this copies the pointer, not the object!
// ...
auto ptr = *reinterpret_cast<A**>(buffer.data()); // is this UB?
delete ptr;
Cuál es el uso de reinterpret_cast
en este caso UB? Yo diría que sí, porque memcpy
no comienza la vida útil de una instancia, por lo tanto, viola la estricta regla de alias (por eso std::bit_cast
se ha agregado a C ++ 20).
Y si reemplazo el elenco con otro memcpy
(para leer el puntero), ¿estaría bien definido el programa?
c++
language-lawyer
Timo
fuente
fuente
buffer.data()
que supuestamente contiene un puntero aA
, no es abuffer.data()
sí mismo a lo que apuntaA
.std::vector
? (Supongo que sus garantías son cualesquiera que sean las garantías de su asignador.)A*
objeto en el búfer. El estándar dice acerca de la función allocator :: allocate estándar: "Devuelve: Un puntero al elemento inicial de una matriz de almacenamiento de tamañon * sizeof(T)
, alineado apropiadamente para objetos de tipo T ".Respuestas:
Sí, este código tiene un comportamiento indefinido. No hay ningún objeto de tipo
A*
en la ubicación que señalabuffer.data()
. Todo lo que hizo fue copiar la representación del objeto de dicho puntero en su vector [basic.types] / 4 . Dado que los punteros se pueden copiar trivialmente [basic.types] / 9 , si copiara estos bytes en un objeto de tipo realA*
y luegodelete
el valor de eso, eso estaría bien definido [basic.types] / 3 . Así que estoestaría bien.
Tenga en cuenta que no es el lanzamiento en sí lo que invoca un comportamiento indefinido en su ejemplo original, sino su intento posterior de leer el valor de un objeto de tipo
A*
que no existe donde el puntero se obtuvo a través de los puntos de lanzamiento. Todo lo que existe donde el puntero apunta es una secuencia de objetos de tipounsigned char
. El tipoA*
no es un tipo que pueda usar para acceder al valor almacenado de un objeto de tipounsigned char
[basic.lval] / 8 ...fuente
A* a_ptr; std::memcpy(&a_ptr, buffer.data(), sizeof(a_ptr));
para extraer el puntero fuera del búfer. En lugar de lareinterpret_cast
pregunta de Timo.unsigned char
allí, tal vez más de uno.