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

为什么C++中访问已delete的悬空指针不会导致程序崩溃?

问题解答

示例代码

#include <iostream>
#include<list>

using namespace std;
template <class T>
class Ptr {
public:
    Ptr() {
        a = nullptr;
        l.push_back(0);
    }

std::list<int> l;
void print_this() {
    cout<<this<<endl;
}

protected:
    int *a;
};

int main()
{
    Ptr<int> *ptr = new Ptr<int>();
    delete ptr;
    //ptr = nullptr; //取消该行注释程序会崩溃
    auto p = &(ptr->l);  
    cout<<"p is "<<p<<endl;
    ptr->print_this();
    ptr->l.push_back(1);
    cout<<"size is "<<ptr->l.size()<<endl;
    cout<<"end";
    return 0;
}

现象原因

你观察到的是C++标准明确定义的未定义行为(Undefined Behavior, UB),当前运行结果完全是巧合,不代表代码逻辑合法。具体原因如下:

  • delete操作仅会告知堆内存分配器对应地址的内存已不再使用,分配器可将其回收供后续new操作复用。该操作不会主动清空内存内容,也不会立刻向操作系统申请将该地址段标记为不可访问。只要这块内存未被其他操作覆盖、也没有被操作系统回收,对它的读写暂时不会触发硬件异常。
  • 未将ptr设为nullptr时,ptr仍保存原来的对象地址,虽然对象已被销毁,但对应地址的内存数据暂时未被改动,类内list的内部控制结构还保持完好:
    • 非虚成员函数print_this的调用不需要访问对象内部数据,仅把ptr的值作为this参数传入函数打印,不会触发错误
    • 访问ptr->l、调用push_back时,用到的list内部头指针、长度等数据还未被破坏,push_back会新申请堆内存存储节点,不会触发异常,所以运行后会输出size为2的结果
  • 将ptr设为nullptr后,访问ptr->l相当于访问0地址偏移的内存,属于操作系统明确禁止的非法访问行为,会立刻触发段错误导致程序崩溃。

注意:这种"正常运行"的状态完全不可靠,只要在delete之后增加任意堆内存申请操作,或者更换运行环境、编译参数,都可能直接导致程序崩溃、输出乱码等不可预期的结果,悬空指针访问的代码禁止在生产环境使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 04:15:02