在C++中,是否定义了删除基元类型(如通过 char* uint32_t)的行为
In C++, is it defined behaviour to delete a primitive type such as uint32_t through a char*?
以下是否定义了行为?
uint32_t* p = new uint32_t();
char* p2 = reinterpret_cast<char*>(p);
delete p2;
(有与此相关的标准报价吗?
我知道有其他选择,但我只是对这个很好奇。
谢谢!
来自 C++17 标准的 [expr.delete]/3(尽管此规则可以追溯到 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
为创建它们的类型,或者对于多态类型,请确保 Deleter virtual