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

如何避免C++析构函数中的double free问题?

问题分析与解决方案

问题根源:并非竞争条件,而是浅拷贝导致的重复释放

你的问题不是竞争条件(竞争条件多出现于多线程场景,由多个线程同时操作同一块内存引发),核心原因是浅拷贝:

UDPCPMessage类的拷贝构造函数和赋值运算符仅直接复制_udpcpChecksum指针,没有为新对象分配独立的内存空间。这导致原对象与拷贝生成的对象共享同一块堆内存:

  • 当main函数中的udpcp对象,以及sendAck函数里的形参对象(通过拷贝生成)各自析构时,都会调用delete _udpcpChecksum,对同一块内存执行两次释放,最终触发double free错误。

从程序输出也能验证:两次trying to delete对应两个对象的析构流程,最终引发内存释放冲突。


更优解决方案

1. 实现深拷贝

为拷贝构造函数和赋值运算符分配独立内存,确保每个对象拥有专属的UDPCPChecksum实例:

// 拷贝构造函数:为新对象创建独立的UDPCPChecksum实例
UDPCPMessage::UDPCPMessage(const UDPCPMessage& udpcpMessage)
{
    cout << "copy constructor called" << endl;
    _udpcpChecksum = new UDPCPChecksum(*udpcpMessage._udpcpChecksum);
}

// 赋值运算符:遵循异常安全原则,先分配新内存再释放旧内存
UDPCPMessage& UDPCPMessage::operator=(const UDPCPMessage& udpcpMessage)
{
    cout << "assignment called" << endl;
    if (this != &udpcpMessage) { // 避免自赋值导致的错误
        // 先创建临时对象,防止new失败丢失旧内存
        UDPCPChecksum* temp = new UDPCPChecksum(*udpcpMessage._udpcpChecksum);
        delete _udpcpChecksum;
        _udpcpChecksum = temp;
    }
    return *this;
}

2. 使用智能指针替代裸指针

借助C++标准库的智能指针自动管理内存,无需手动编写析构、拷贝构造和赋值运算符:

  • 如果UDPCPChecksum的所有权仅属于单个UDPCPMessage,使用std::unique_ptr(独占所有权,默认禁用拷贝,从根源避免浅拷贝):
#include <memory>

class UDPCPMessage
{
    std::unique_ptr<UDPCPChecksum> _udpcpChecksum;
    int A;
public:
    UDPCPMessage() : _udpcpChecksum(std::make_unique<UDPCPChecksum>()) {
        cout << "default constructor called" << endl;
    }
    UDPCPMessage(const std::string& msg) : _udpcpChecksum(std::make_unique<UDPCPChecksum>()) {
        cout << "parameter constructor called" << endl;
    }
    // 无需手动编写析构函数,unique_ptr会自动释放内存
};
  • 如果需要多个对象共享UDPCPChecksum,使用std::shared_ptr(通过引用计数管理内存,最后一个对象销毁时才释放):
#include <memory>

class UDPCPMessage
{
    std::shared_ptr<UDPCPChecksum> _udpcpChecksum;
    int A;
public:
    UDPCPMessage() : _udpcpChecksum(std::make_shared<UDPCPChecksum>()) {
        cout << "default constructor called" << endl;
    }
    // 拷贝构造和赋值运算符会自动维护引用计数,无需手动实现
};

3. 禁止拷贝操作

如果UDPCPMessage对象不需要被拷贝,直接禁用拷贝构造和赋值运算符,提前阻断浅拷贝可能:

class UDPCPMessage
{
    UDPCPChecksum* _udpcpChecksum;
    int A;
public:
    UDPCPMessage();
    UDPCPMessage(const std::string& msg);
    ~UDPCPMessage();
    // 显式禁用拷贝构造和赋值运算符
    UDPCPMessage(const UDPCPMessage&) = delete;
    UDPCPMessage& operator=(const UDPCPMessage&) = delete;
};

此时若代码中出现拷贝UDPCPMessage的操作(比如sendAck按值传参),编译器会直接报错,提前发现问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 19:24:58