Является ли использование reinterpret_cast в буфере memcpy UB? - PullRequest
8 голосов
/ 13 января 2020

Учитывая код

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;

, является ли использование reinterpret_cast в этом случае UB? Я бы сказал да, потому что memcpy не запускает время жизни экземпляра, поэтому нарушает правило строгого алиасинга (именно поэтому std::bit_cast был добавлен в C ++ 20).

И если я заменить приведение другим memcpy (чтобы прочитать указатель), будет ли программа хорошо определена?

1 Ответ

9 голосов
/ 13 января 2020

Да, этот код имеет неопределенное поведение. В месте, указанном buffer.data(), нет объекта типа A*. Все, что вы сделали, это скопировали объектное представление такого указателя в ваш вектор [basi c .types] / 4 . Поскольку указатели легко копируются [basi c .types] / 9 , если вы скопируете эти байты обратно в реальный объект типа A*, а затем delete значение этого, то будет четко определено [basi c .types] / 3 . Так что это

A* ptr;
std::memcpy(&ptr, buffer.data(), sizeof(ptr));
delete ptr;

было бы хорошо.

Обратите внимание, что не само приведение вызывает неопределенное поведение в вашем исходном примере, а ваша последующая попытка прочитать значение объекта типа A* который не существует там, где указатель получен через точки приведения. Все существует там, где указатель указывает на последовательность объектов типа unsigned char. Тип A* не является типом, который вы можете использовать для доступа к сохраненному значению объекта типа unsigned char [basi c .lval] / 8

...