在C++中,是否定义了删除基元类型(如通过 char* uint32_t)的行为

In C++, is it defined behaviour to delete a primitive type such as uint32_t through a char*?

本文关键字:uint32 char 是否 C++ 定义 类型 删除      更新时间:2023-10-16

以下是否定义了行为?

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