在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 并且可能更早,但我手边没有那个规范):
if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
被指向对象的动态类型是uint32_t
。指针的类型是char
。它们不相同,char
也不是 uint32_t
的基础 class,因此行为未定义。
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
.
以下是否定义了行为?
uint32_t* p = new uint32_t();
char* p2 = reinterpret_cast<char*>(p);
delete p2;
(是否有与此相关的标准报价?)
我知道存在其他选项,但我只是对这个感到好奇。
谢谢!
来自 C++17 标准中的 [expr.delete]/3(虽然这条规则可以追溯到 C++11 并且可能更早,但我手边没有那个规范):
if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
被指向对象的动态类型是uint32_t
。指针的类型是char
。它们不相同,char
也不是 uint32_t
的基础 class,因此行为未定义。
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
.