在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

简而言之,deleteint* 的程序集计算的要存储在寄存器中的字节数与 deletechar* 的程序集不同。

所以从表面上看,很明显编译器识别的类型很重要。即使没有其他原因,只是为了确保删除正确数量的内存。因此,您不能依赖编译器神奇地推断出 delete 类型已被 reinterpret_cast 调用更改的指针的正确行为:您需要确保 delete指针作为它们被创建的类型——或者对于多态类型,确保 Deleter 是 virtual.