为何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。
原因分析
对象内存在第一次
delete后已被回收
第一次调用delete p时,析构函数正常执行,确实把pstr置为了NULL。但析构完成后,p指向的内存块会被堆管理器回收,这块内存变成了已释放的无效内存,程序不再拥有它的使用权。重复
delete属于未定义行为
C++标准明确规定,对同一个指针执行多次delete是未定义行为。堆管理器可能会修改已释放内存的内容,或者将其分配给其他对象。所以第二次调用析构函数时,读取的pstr值是堆管理器篡改后的无效值,不再是第一次析构时设置的NULL。置NULL操作无法作用于已释放的内存
第一次析构中对pstr的赋值仅在对象内存存活时有效。当内存被回收后,这个修改的结果已经不受程序控制,后续访问这块内存中的数据完全不可靠。
简单来说,重复delete本身就是违规操作,触发的未定义行为导致了成员变量值异常。
内容的提问来源于stack exchange,提问作者dragonfly
相关产品推荐
相关产品推荐

