重载赋值运算符时为何会两次调用析构函数?
问题原因与修复方案
你的问题核心出在赋值运算符的返回值类型,以及由此引发的临时对象拷贝和浅拷贝问题:
赋值运算符返回值错误
你定义的赋值运算符:BoomPoiner operator=(Boom *obj){ this->obj = obj; cout << "= operator... " << this << endl; return *this; }返回的是
BoomPoiner值类型,而非引用类型。执行ptr = boom时,赋值完成后会创建一个ptr的临时副本(运行日志里的Copy constructor... 0x16fdff298就是这个临时对象被构造的过程)。这个临时对象和原ptr共享同一个Boom* obj指针。重复释放导致double free
临时对象生命周期结束时会调用析构函数,先delete obj释放了Boom实例;当函数makePointer执行完毕,原ptr对象销毁时,又会再次delete obj,这就触发了double free错误——同一个内存块被释放两次。额外问题:未初始化的指针
BoomPoiner的构造函数没有初始化obj成员,默认是野指针状态,如果在未赋值的情况下析构,会导致未定义行为。
修复方案
1. 修正赋值运算符,返回引用
按C++惯例,赋值运算符应返回自身的引用,避免临时对象产生:
BoomPoiner& operator=(Boom *obj){ this->obj = obj; cout << "= operator... " << this << endl; return *this; }
2. 处理所有权问题(可选,类似智能指针)
因为你的类是模拟智能指针,应该确保Boom实例的所有权唯一。可以禁用拷贝构造和赋值运算符(避免浅拷贝):
// 禁用拷贝构造 BoomPoiner(const BoomPoiner&) = delete; // 禁用拷贝赋值 BoomPoiner& operator=(const BoomPoiner&) = delete;
3. 初始化指针成员
在构造函数里初始化obj为nullptr,避免野指针:
BoomPoiner(int a): no(a), obj(nullptr){ cout << "Create pointer... " << this << endl; }
修复后的完整代码示例
#include <iostream> #include <memory> using namespace std; class Boom{ private: int no; public: Boom():no(10){ //cout << "Create Boom 1..." << endl; } Boom(int a):no(a) { //cout << "Create Boom 2..." << endl; }; ~Boom(){ //cout << "Destructing.." << " " << no << endl; }; }; class BoomPoiner { private: Boom* obj; int no; public: BoomPoiner(int a): no(a), obj(nullptr){ cout << "Create pointer... " << this << endl; } // 禁用拷贝构造和拷贝赋值 BoomPoiner(const BoomPoiner&) = delete; BoomPoiner& operator=(const BoomPoiner&) = delete; BoomPoiner& operator=(Boom *obj){ this->obj = obj; cout << "= operator... " << this << endl; return *this; } ~BoomPoiner(){ cout << "Delete pointer obj... " << this << " " << no << endl; delete obj; } }; void makePointer(){ Boom* boom = new Boom(); BoomPoiner ptr(1); ptr = boom; cout << "out func" << endl; return; } int main(){ makePointer(); return 0; }
运行修复后的代码,只会调用一次BoomPoiner的析构函数,不会再出现double free错误。
内容的提问来源于stack exchange,提问作者just_code_dog
相关产品推荐
相关产品推荐

