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

矩阵构造后析构函数抛出异常,求故障原因

矩阵析构函数抛出访问违规异常排查

问题描述

用双指针实现矩阵类时,程序在析构函数调用阶段抛出读取访问违规异常,错误信息如下:

Exception thrown: read access violation.
this->array was 0x111011101110112.

怀疑问题出在移动/拷贝构造函数或初始化构造函数中,多次调试仍无法定位,附上代码请求排查。

代码片段

Matrix.h

#pragma once
#include <iostream>

class Matrix {
    size_t rows;
    size_t cols;
    int** array;
public:
    ~Matrix();
    Matrix(size_t, size_t);
    Matrix(const Matrix&);
    Matrix(Matrix&&);
    Matrix(size_t, size_t, std::initializer_list<std::initializer_list<int>>);
};

Matrix.cpp

#include "Matrix.h"

Matrix::~Matrix() {
    for (size_t i = 0; i < rows; i++) {
        delete[] array[i];
    }
    delete[] array;
}

Matrix::Matrix(size_t rows, size_t cols)
    : rows(rows), cols(cols), array(new int* [rows]) {
    for (size_t i = 0; i < rows; i++) {
        array[i] = new int[cols];
    }
    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++) {
            array[i][j] = 0;
        }
    }
    std::cout << "CONSTRUCTOR" << std::endl;
}

Matrix::Matrix(size_t rows, size_t cols, std::initializer_list<std::initializer_list<int>> list)
    : rows(rows), cols(cols), array(new int* [rows]) {
    for (size_t i = 0; i < rows; i++) {
        array[i] = new int[cols];
    }
    size_t i = 0;
    for (auto row : list) {
        size_t j = 0;
        for (auto elem : row) {
            array[i][j] = elem;
            j++;
        }
        i++;
    }
}

Matrix::Matrix(const Matrix& other)
    : rows(other.rows), cols(other.cols), array(new int* [other.rows]) {
    if (other.array != nullptr) {
        for (size_t i = 0; i < other.rows; i++) {
            array[i] = new int[other.cols];
        }
        for (size_t i = 0; i < other.rows; i++) {
            for (size_t j = 0; j < other.cols; j++) {
                array[i][j] = other.array[i][j];
            }
        }
    }
    else {
        delete[] array;
        array = nullptr;
    }
    std::cout << "COPY" << std::endl;
}

Matrix::Matrix(Matrix&& other)
    : rows(other.rows), cols(other.cols), array(other.array) {
    other.array = nullptr;
    std::cout << "MOVE" << std::endl;
}

main.cpp

#include "Matrix.h"

Matrix f(Matrix m) { return m; }

int main() {
    Matrix m(2, 2, { {1,2},{2,3} });
    Matrix k(f(m));
}

问题根源及修复方案

1. 移动构造函数未重置原对象的行数和列数

移动构造函数仅将原对象的array置为nullptr,但保留了rows和cols的原值。当原对象(比如函数f的形参m)被析构时,会循环rows次尝试访问array[i],此时array已经是空指针,直接触发读取访问违规。

修复代码:

Matrix::Matrix(Matrix&& other)
    : rows(other.rows), cols(other.cols), array(other.array) {
    // 重置原对象所有成员,避免析构时出错
    other.array = nullptr;
    other.rows = 0;
    other.cols = 0;
    std::cout << "MOVE" << std::endl;
}

2. 析构函数未做空指针检查

当array为nullptr时,直接循环访问array[i]会导致非法内存访问,需要先判断array是否有效。

修复代码:

Matrix::~Matrix() {
    if (array != nullptr) {
        for (size_t i = 0; i < rows; i++) {
            delete[] array[i];
        }
        delete[] array;
    }
}

3. 拷贝构造函数冗余逻辑优化(可选)

原拷贝构造函数中other.array不可能为nullptr——所有构造函数都会初始化array为有效指针,移动后的对象rows为0,拷贝时不会进入else分支。可以简化逻辑,同时用std::copy减少循环次数:

Matrix::Matrix(const Matrix& other)
    : rows(other.rows), cols(other.cols), array(new int* [other.rows]) {
    for (size_t i = 0; i < other.rows; i++) {
        array[i] = new int[other.cols];
        std::copy(other.array[i], other.array[i] + other.cols, array[i]);
    }
    std::cout << "COPY" << std::endl;
}

4. 初始化列表构造函数越界风险修复(可选)

如果传入的初始化列表行数/列数与指定的rows/cols不匹配,会导致数组越界,可添加参数合法性检查:

#include <stdexcept> // 需要包含头文件

Matrix::Matrix(size_t rows, size_t cols, std::initializer_list<std::initializer_list<int>> list)
    : rows(rows), cols(cols), array(new int* [rows]) {
    if (list.size() != rows) {
        throw std::invalid_argument("初始化列表行数与指定行数不匹配");
    }
    // 先初始化所有元素为默认值
    for (size_t i = 0; i < rows; i++) {
        array[i] = new int[cols];
        std::fill(array[i], array[i] + cols, 0);
    }
    size_t i = 0;
    for (auto row : list) {
        if (row.size() > cols) {
            throw std::invalid_argument("初始化列表列数超过指定列数");
        }
        size_t j = 0;
        for (auto elem : row) {
            array[i][j] = elem;
            j++;
        }
        i++;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:25:34