В C++ определено ли поведение для удаления примитивного типа, такого как uint32_t, через char*?
Определенное поведение имеет следующее?
uint32_t* p = new uint32_t();
char* p2 = reinterpret_cast<char*>(p);
delete p2;
(Существует ли стандартная цитата, относящаяся к этому?)
Я знаю, что существуют альтернативные варианты, но мне просто любопытно об этом.
Спасибо!
2 ответа
От [expr.delete]/3 в стандарте C++17 (хотя это правило восходит к C++11 и, возможно, к более раннему, но у меня нет этой спецификации под рукой):
если статический тип удаляемого объекта отличается от его динамического типа, статический тип должен быть базовым классом динамического типа удаляемого объекта, а статический тип должен иметь виртуальный деструктор или поведение не определено.
Динамический тип объекта, на который указывает uint32_t
, Тип указателя char
, Это не то же самое, и не является char
базовый класс uint32_t
, поэтому поведение не определено.
Определенно нет эквивалента 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
char*
делает.
Итак, на первый взгляд, ясно, что тип, который распознает компилятор, имеет значение. Даже если нет другой причины, кроме как гарантировать, что правильный объем памяти будет удален. Таким образом, вы не можете полагаться на то, что компилятор волшебным образом выведет правильное поведение для delete
указатель, тип которого был изменен reinterpret_cast
позвоните: вам нужно убедиться, что delete
указатели как тип, который они были созданы, или для полиморфных типов, убедитесь, что средство удаления virtual
,