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

为何C++类析构函数中成员变量值两次调用时不一致?

问题:重复delete对象后析构函数中pstr为何未被置为NULL?

我编写了一个测试析构函数行为的Demo,但输出结果不符合预期。

源码

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Str{
private:
    char *pstr;
public:
    Str(char value[])
    {
        cout<<this<<":constructor called"<<endl;
        pstr = NULL;
        int len = strlen(value);
        pstr = (char *)malloc(len + 1);
        memset(pstr,0,len + 1);
        strcpy(pstr,value);
    }
    ~Str()
    {
        cout<<this<<":destructor called, "<<(long)pstr<<endl;
        if(pstr != NULL)
        {
            cout<<this<<":destructor call free() "<<endl;
            free(pstr);
            pstr = NULL;
        }
    }
};
int main()
{
    Str *p = new Str("aaa");
    delete p;
    delete p; //make destuctor called twice.
    return 0; 
}

程序输出

0x600001240040:constructor called
0x600001240040:destructor called, 105553135403088
0x600001240040:destructor call free()
0x600001240040:destructor called, 255133788340288
0x600001240040:destructor call free()
a.out(71425,0x1fdc8e080) malloc: *** error for object 0xe80af6d30040: pointer being freed was not allocated
a.out(71425,0x1fdc8e080) malloc: *** set a breakpoint in malloc_error_break to debug
Abort trap: 6

观察输出可知,第二次调用析构函数时成员变量pstr为何不为NULL?明明第一次调用析构函数时已将其赋值为NULL。


原因分析
  1. 对象内存在第一次delete后已被回收
    第一次调用delete p时,析构函数正常执行,确实把pstr置为了NULL。但析构完成后,p指向的内存块会被堆管理器回收,这块内存变成了已释放的无效内存,程序不再拥有它的使用权。

  2. 重复delete属于未定义行为
    C++标准明确规定,对同一个指针执行多次delete是未定义行为。堆管理器可能会修改已释放内存的内容,或者将其分配给其他对象。所以第二次调用析构函数时,读取的pstr值是堆管理器篡改后的无效值,不再是第一次析构时设置的NULL。

  3. 置NULL操作无法作用于已释放的内存
    第一次析构中对pstr的赋值仅在对象内存存活时有效。当内存被回收后,这个修改的结果已经不受程序控制,后续访问这块内存中的数据完全不可靠。

简单来说,重复delete本身就是违规操作,触发的未定义行为导致了成员变量值异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 22:12:42