В C ++ определено ли поведение для удаления примитивного типа, такого как uint32_t, через char *? - PullRequest
0 голосов
/ 17 января 2019

Имеет ли следующее поведение определенное поведение?

uint32_t* p = new uint32_t();

char* p2 = reinterpret_cast<char*>(p);

delete p2;

(Существует ли стандартная цитата, относящаяся к этому?)

Я знаю, что существуют альтернативные варианты, но мне просто интересно узнать об этом.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 17 января 2019

Определенно нет эквивалента между delete int_ptr; и delete char_ptr;, основанным на сборке, скомпилированной из некоторого базового кода C ++:

//C++ Code
void delete_as_int(int* ptr) {
    delete ptr;
}

void delete_as_char(char* ptr) {
    delete ptr;
}

//Assembly; GCC 8.2 x86-64, no optimizations, c++17 mode
delete_as_int(int*):
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov QWORD PTR [rbp-8], rdi
  mov rax, QWORD PTR [rbp-8]
  mov esi, 4 //Difference!
  mov rdi, rax
  call operator delete(void*, unsigned long)
  nop
  leave
  ret
delete_as_char(char*):
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov QWORD PTR [rbp-8], rdi
  mov rax, QWORD PTR [rbp-8]
  mov esi, 1 //Difference!
  mov rdi, rax
  call operator delete(void*, unsigned long)
  nop
  leave
  ret

Проще говоря, сборка delete и int*вычисляет другое количество байтов для хранения в регистре, чем сборка для delete a char*.

Итак, на первый взгляд, ясно, что тип, который распознает компилятор, имеет значение.Даже если нет другой причины, кроме как гарантировать, что правильный объем памяти будет удален.Таким образом, вы не можете полагаться на то, что компилятор волшебным образом выведет правильное поведение для delete указателя, тип которого был изменен вызовом reinterpret_cast: вам нужно убедиться, что указатели delete являются типом, которым они былисозданный как - или для полиморфных типов, убедитесь, что Deleter имеет значение virtual.

0 голосов
/ 17 января 2019

С [expr.delete] / 3 в стандарте C ++ 17 (хотя это правило восходит к C ++ 11 и, возможно, к более раннему, но у меня нет этой спецификации под рукой) :

если статический тип удаляемого объекта отличается от его динамического типа, статический тип должен быть базовым классом динамического типа удаляемого объекта, а статический тип должен иметь виртуальный деструктор или поведение не определено.

Динамический тип объекта, на который указывает объект, - uint32_t. Тип указателя char. Это не то же самое, и char не является базовым классом uint32_t, поэтому поведение не определено.

...