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

重载赋值运算符时为何会两次调用析构函数?

问题原因与修复方案

你的问题核心出在赋值运算符的返回值类型,以及由此引发的临时对象拷贝和浅拷贝问题:

  1. 赋值运算符返回值错误
    你定义的赋值运算符:

    BoomPoiner operator=(Boom *obj){
        this->obj = obj;
        cout << "= operator... " << this << endl;
        return *this;
    }
    

    返回的是BoomPoiner值类型,而非引用类型。执行ptr = boom时,赋值完成后会创建一个ptr的临时副本(运行日志里的Copy constructor... 0x16fdff298就是这个临时对象被构造的过程)。这个临时对象和原ptr共享同一个Boom* obj指针。

  2. 重复释放导致double free
    临时对象生命周期结束时会调用析构函数,先delete obj释放了Boom实例;当函数makePointer执行完毕,原ptr对象销毁时,又会再次delete obj,这就触发了double free错误——同一个内存块被释放两次。

  3. 额外问题:未初始化的指针
    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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 08:57:09