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

为什么C++使用赋值运算符时数组未释放且报double free错误

问题根因分析

你遇到的free(): double free detected in tcache 2错误完全是赋值运算符的错误实现导致的,核心问题是你在赋值逻辑中直接拷贝了堆内存指针,让两个独立的类实例共享了同一块堆内存,最终析构时重复释放同一块地址触发报错。


疑问逐一解答
  • 新实例的数组为什么没有被释放?
    你在赋值运算符中直接执行了arr = other.arr,直接覆盖了左值对象(也就是代码里的m)原本持有的堆内存指针,m初始化时申请的那部分内存的地址直接丢失,没有任何指针能访问到这部分内存,自然也无法被释放,属于内存泄漏。
  • 难道第二个实例运行时不该自动释放对应资源吗?
    第二个实例n的资源会被自动释放,恰恰是因为它的资源被正常释放了才会触发double free报错。赋值操作后m.arr和n.arr指向完全相同的堆内存地址,main函数退出时栈对象按构造逆序析构:先析构n释放了这块内存,再析构m时又尝试释放已经被释放的同一块内存,就触发了报错。
  • 为什么析构函数对n实例没有生效?
    析构函数对n完全生效了,报错的原因不是析构没生效,是两个实例共享内存导致重复释放。你可以在析构函数中加打印输出实例的地址和arr的地址,就能清楚看到两个实例的arr值完全相同,各触发一次释放操作。
  • 是否需要在赋值运算符中手动释放n的arr?
    完全不需要,n的资源由n自己的生命周期管理,赋值运算符只需要负责处理左值对象(也就是=左边的实例)的资源即可,不要越权操作右值对象的内部资源。

修复方案

你需要重新实现赋值运算符,按照深拷贝的逻辑完成赋值:

  1. 首先判断是否是自赋值,如果是直接返回自身,避免释放自身资源后无法访问右值数据
  2. 先释放左值对象原本持有的所有堆内存,避免内存泄漏
  3. 按照拷贝构造的逻辑,重新申请对应大小的内存,再逐元素拷贝右值的数据,不要直接拷贝指针

修正后的赋值运算符代码如下:

spMatrix& operator = (spMatrix const & other){
    // 自赋值判断,避免出错
    if (this == &other) {
        return *this;
    }
    // 第一步:释放当前对象原本持有的资源
    if(arr != NULL){
        for (int i = 0; i < N; i++) {
            if (arr[i] != NULL) delete [] arr[i];
        }
        delete [] arr;
    }
    // 第二步:深拷贝右值对象的内容
    N = other.N;
    arr = new double* [N];
    for (int i = 0; i < N; ++i) {
        arr[i] = new double [N];
        for (int j = 0; j < N; ++j) {
            arr[i][j] = other.arr[i][j];
        }
    }
    return *this;
}

如果想写更安全的实现,也可以用拷贝交换(copy-and-swap)的写法,能自动处理自赋值、异常安全的问题,不需要手动写重复的释放和拷贝逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 01:45:04