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

深拷贝操作引发Double free问题的两类技术疑问

Line类双释放问题及相关疑问解答

原代码中Line pCopy; pCopy = pLine->deep_copy();会触发Double free错误,核心原因是默认赋值运算符的浅拷贝导致指针被重复释放。以下针对两个疑问逐一解答:


疑问1:Line pCopy = pLine->deep_copy();与原写法的差异

原写法执行流程

  1. Line pCopy;:调用默认构造函数,pCopy的start和end被初始化为nullptr。
  2. pCopy = pLine->deep_copy();:
    • 先执行deep_copy(),创建两个新的Point对象,返回一个临时Line对象(持有这两个新指针)。
    • 调用默认赋值运算符,将临时对象的start和end指针直接赋值给pCopy(浅拷贝)。
    • 临时对象生命周期结束,调用析构函数delete掉这两个Point指针,导致pCopy的指针变成野指针。
    • main函数结束时,pCopy的析构函数再次delete野指针,触发Double free错误。

修复写法执行流程

Line pCopy = pLine->deep_copy();属于拷贝初始化:

  • 编译器会直接用deep_copy()返回的结果构造pCopy(C17及以后标准强制消除临时对象的拷贝,直接在pCopy的内存空间构造返回值;C17前多数编译器也会做返回值优化RVO,跳过临时对象的创建)。
  • 整个过程中只有pCopy持有新创建的Point指针,临时对象不会被创建(或被优化掉),因此只有pCopy销毁时会调用一次析构函数,不会出现重复释放。

疑问2:实现拷贝构造函数后,修复写法调用拷贝构造而非直接使用deep_copy()结果的原因及解决方法

原因

Line pCopy = pLine->deep_copy();的拷贝初始化语法,在C++17之前的语义是:

  1. 先执行deep_copy()得到临时Line对象。
  2. 调用拷贝构造函数,将临时对象的内容拷贝到pCopy中。
    即使编译器做RVO优化,这只是编译器的行为,并非标准强制要求。当你自定义了拷贝构造函数后,编译器会严格按照语法规则调用它(除非触发优化)。

而C++17及以后,标准强制要求复制消除,此时编译器会直接在pCopy的内存空间构造deep_copy()的返回值,不会调用拷贝构造函数。

解决方法

  1. 升级到C++17或更高版本:利用标准强制的复制消除,直接跳过拷贝构造函数,将deep_copy()的结果直接构造到pCopy中。
  2. 定义移动构造函数:如果无法升级编译器,可给Line类添加移动构造函数,让临时对象的指针所有权直接转移给pCopy,避免拷贝:
    Line(Line&& other) noexcept : start(other.start), end(other.end) {
        other.start = nullptr;
        other.end = nullptr;
    }
    
    此时Line pCopy = pLine->deep_copy();会调用移动构造函数,将临时对象的指针转移后,临时对象的析构函数不会释放指针(因为已经被置为nullptr),既避免了拷贝,也不会触发Double free。
  3. 改用直接初始化语法:写法上更清晰,本质和拷贝初始化一致:
    Line pCopy(pLine->deep_copy());
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 16:54:52