You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中删除非new分配内存构造的对象为何引发段错误?

关于C++中placement new与delete不兼容的问题

我阅读了一篇关于new/operator new的文章,其中遇到一段无法理解的示例代码:

int main(int argc, const char* argv[])
{
    char mem[sizeof(int)];
    int* iptr2 = new (mem) int;

    delete iptr2;       // 糟糕,段错误!

    return 0;
}

这段代码里int的内存并非通过普通new分配,执行delete会触发段错误。我想知道delete在此处不兼容的具体原因是什么?使用new初始化对象时是否存在delete会查找的隐藏结构?


编辑补充

  • 正如网友指出的,mem是在栈上分配的内存,而delete的作用是释放堆内存,这种不匹配在多数架构下都会引发段错误。
  • 若mem在堆上分配但未使用合适的new:
    我试过的唯一方式是先在堆上分配int*,再通过reinterpret_cast转换为char数组,之后把这个char指针传入delete。在我测试的几种架构中代码能运行,但会导致内存泄漏。而且C++标准并不保证这种写法的有效性,因为它依赖底层架构的绑定假设。

问题解答

1. delete触发段错误的核心原因

  • 内存区域不匹配:delete的设计目标是释放堆内存。当使用普通new(如int* p = new int;)时,operator new会从堆中申请内存,底层分配器会记录这块内存的元信息(比如大小、分配位置标记等)。而示例中的mem是栈上的自动存储变量,栈内存的生命周期由编译器自动管理,delete没有权限也没有逻辑去释放栈内存,强行调用会直接触发内存访问错误(段错误)。
  • placement new的特殊性:你用到的new (mem) int是placement new,它的作用仅仅是在已有的内存块上构造对象,完全不涉及内存分配——既不会向堆申请内存,也不会和底层分配器交互记录元信息。因此delete找不到对应堆内存的管理信息,自然无法正确执行释放操作。

2. 关于"隐藏结构"的说明

普通new分配内存时,分配器通常会在返回给你的指针**前方(或固定偏移位置)**存储元信息:比如内存块的大小、堆分配标记等。delete执行时会先读取这些元信息,确定要释放的内存范围、调用正确的析构逻辑,再通知分配器回收内存。但placement new不会生成这些元信息,因为它根本不负责内存分配,所以delete拿到iptr2后,会错误地去栈内存区域查找不存在的元信息,进而触发段错误。

3. 堆内存场景的补充说明

如果mem是堆上分配的内存(比如char* mem = new char[sizeof(int)];),此时用placement new构造对象后,直接delete iptr2依然是错误的:

  • iptr2指向的内存是由new char[]分配的,正确的释放方式应该是delete[] mem;,delete和new、delete[]和new[]必须严格配对,否则会导致分配器元信息混乱,轻则内存泄漏,重则程序崩溃。
  • 你提到的reinterpret_cast转换后调用delete能运行属于未定义行为,C++标准不做任何保证,不同编译器、架构下可能出现完全不同的结果,绝对不能在生产代码中使用。

内容的提问来源于stack exchange,提问作者LazyCat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 23:45:47