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

模板矩阵类拷贝构造器未处理异常问题求助

模板矩阵类的未处理异常问题分析与修复

遇到的错误:

未处理异常: 0x00007FF60FEC7836 (hw2.exe): 0xC0000005: 读取位置 0xFFFFFFFFFFFFFFFF 时发生访问违规。

核心问题:运算符*返回局部对象的引用

先看这段运算符重载代码:

template<int Rows, int Cols, class T = int>
Matrix<Rows, Cols>& operator*(int n, const Matrix<Rows, Cols>& mat) {
    Matrix<Rows, Cols> temp;
    for (int i = 0;i < Rows;i++) {
        for (int j = 0;j < Cols;j++) {
            std::cout << "in the * operator" << std::endl;
            temp.data[i][j] = mat.data[i][j] * n;
        }
    }
    return temp;
}

函数内的temp是局部栈对象,当函数执行完毕时,temp会被销毁,其占用的内存会被系统回收。此时返回temp的引用,得到的是一个悬空引用——指向已经被释放的内存空间。后续代码访问这个引用时,就会触发内存访问违规错误。

注意:返回值完全可以支持链式操作(比如(mat +2)*3),不需要返回引用。临时对象的返回会被编译器优化(RVO/NRVO),不会有性能问题。

拷贝构造器的错误实现

拷贝构造器中的两处NULL检查完全错误且多余:

Matrix(const Matrix& other) {
    if (other.data == NULL) {
        this->data = NULL;
        return;
    }
    this->data = new T * [Rows];
    for (int i = 0; i < Rows;i++) {
        this->data[i] = new T[Cols];
        if (other.data[i] != NULL) {
            for (int j = 0;j < Cols;j++) {
                if (other.data[i][j] != NULL) { // 严重错误:非指针类型不能和NULL比较
                    this->data[i][j] = other.data[i][j];
                    std::cout << data[i][j] << std::endl;
                }
            }
        }
    }
}
  • other.data[i][j]是模板类型T(默认是int),不是指针类型,不能和NULL比较,这会导致未定义行为
  • 所有构造器中分配的data和data[i]都是通过new创建的有效指针,不可能为NULL,所以所有NULL判断都多余

修复后的拷贝构造器:

Matrix(const Matrix& other) {
    this->data = new T*[Rows];
    for (int i = 0; i < Rows; i++) {
        this->data[i] = new T[Cols];
        for (int j = 0; j < Cols; j++) {
            this->data[i][j] = other.data[i][j];
        }
    }
}

必须补充的赋值运算符重载

当前代码没有重载赋值运算符,编译器会生成默认的浅拷贝赋值运算符。这会导致两个Matrix对象共享data指针,当其中一个对象析构时,会释放内存,另一个对象再访问data就会触发错误,或者析构时重复释放内存导致崩溃。

添加深拷贝的赋值运算符:

Matrix& operator=(const Matrix& other) {
    if (this == &other) { // 防止自赋值
        return *this;
    }

    // 释放当前对象已有的内存
    for (int i = 0; i < Rows; i++) {
        delete[] data[i];
    }
    delete[] data;

    // 分配新内存并拷贝数据
    data = new T*[Rows];
    for (int i = 0; i < Rows; i++) {
        data[i] = new T[Cols];
        for (int j = 0; j < Cols; j++) {
            data[i][j] = other.data[i][j];
        }
    }
    return *this;
}

最终修复后的运算符*

将返回类型改为值返回,即可解决悬空引用问题,同时支持链式操作:

template<int Rows, int Cols, class T = int>
Matrix<Rows, Cols> operator*(int n, const Matrix<Rows, Cols>& mat) {
    Matrix<Rows, Cols> temp;
    for (int i = 0;i < Rows;i++) {
        for (int j = 0;j < Cols;j++) {
            temp.data[i][j] = mat.data[i][j] * n;
        }
    }
    return temp;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 21:54:57