为什么这个代码片段是段错误?

Why it is a segmentation fault with this code fragment?

这是我关于 Matrix 的代码(我决定练习 OOP 编写自己的 Matrix class)

Matrix.hpp

#ifndef MATRIX_HEADER
#define MATRIX_HEADER

typedef unsigned int u_int;

class Matrix
{
    double **mtrx;
    u_int x, y;

public:
    Matrix(u_int a, u_int b);
    Matrix(const Matrix &);
    ~Matrix();

    double det();

    Matrix operator+(const Matrix &) const;
    Matrix operator-(const Matrix &) const;                           
    Matrix operator*(const Matrix &) const;
    friend Matrix operator*(const Matrix &, const double &);
    Matrix operator/(const Matrix &) const;
    double *operator[](const u_int idx) const { return mtrx[idx]; }

    bool IsEqual(const Matrix &) const;
    u_int GetX() const { return x; }
    u_int GetY() const { return y; }
};

#endif

Matrix.cpp

#include "Matrix.hpp"

Matrix::Matrix(u_int a, u_int b) : x(a), y(b)
{
    mtrx = new double *[x];
    for (u_int i = 0; i < x; i++)
        mtrx[i] = new double[y];
}

Matrix::Matrix(const Matrix &ref)
{
    if (mtrx)
    {
        for (u_int i = 0; i < x; i++)
            delete[] mtrx[i];
        delete[] mtrx;
    }
    x = ref.x;
    y = ref.y;
    *mtrx = new double[x];
    for (u_int i = 0; i < x; i++)
        mtrx[i] = new double[y];
}

Matrix::~Matrix()
{
    if (mtrx)
    {
        for (u_int i = 0; i < x; i++)
            delete[] mtrx[i];
        delete[] mtrx;
    }
}

bool Matrix::IsEqual(const Matrix &a) const     // If sizes of matrixes are equal
{                                               // matrixes are equal
    return (a.GetX() == x) && (a.GetY() == y);
}

Matrix Matrix::operator+(const Matrix &a) const
{
    if (!IsEqual(a))                            // Check on equality matrixes
        return Matrix(1,1);                     // I have not any idea yet what          
    Matrix matrix(x, y);                        // should it give is sizes 
    for (u_int i = 0; i < x; i++)               // of Matrix are not equal
        for (u_int j = 0; j < y; j++)
            matrix[i][j] = a.mtrx[i][j] + mtrx[i][j];
    return matrix;
}

main.cpp

#include <stdio.h>
#include "Matrix.hpp"

int main()
{
    Matrix a(2, 5);
    Matrix b(2, 5);
    for (u_int i = 0; i < a.GetX(); i++)
    {
        for (u_int j = 0; j < a.GetY(); j++)
        {
            a[i][j] = i + j;
        }
    }
    for (u_int i = 0; i < b.GetX(); i++)
    {
        for (u_int j = 0; j < b.GetY(); j++)
        {
            b[i][j] = i + j;
        }
    }
    Matrix c = a + b;
    return 0;
}

当我打开我的程序时,它在添加两个矩阵后抛出一个分段错误。在那种情况下对我来说更有趣的是 Matrix.cpp, Matrix Matrix::operation+....

中的前两行

当我删除这两行(检查相等的 2 个矩阵)时,当我打开我的程序时,它不会抛出一个分段错误,但是当我添加这两行时,程序抛出一个 s.f。你能告诉我为什么它会这样吗?

您可以考虑使用一维 double[x*y] 数组而不是 double[y] 数组的二维 double*[x]。这将使内存管理更容易一些,因为您只需要处理 1 个数组,而不是多个数组。

在任何情况下,你的 Matrix(const Matrix &) 复制构造函数不应该 delete[]mtrx 中任何东西,因为 mtrx 还没有被初始化(它是指向随机内存)。该构造函数的其余部分也没有正确分配数组。您在 Matrix(u_int, u_int) 构造函数中正确分配了数组,因此只需将该逻辑复制到复制构造函数中即可。然后完成复制构造函数,你知道,实际上从被复制的 Matrix 中复制 double 值。

至于 operator+,如果您不知道对于不同大小的矩阵应该 return 什么,那么我建议 throw'ing 一个例外。

此外,即使您当前的代码还没有使用它,您也应该添加一个复制赋值 operator= 来完成 Rule of 3(您已经有一个复制构造函数和一个析构函数) .

试试这个:

#ifndef MATRIX_HEADER
#define MATRIX_HEADER

typedef unsigned int u_int;

class Matrix
{
    double **mtrx;
    //or: double *mtrx;
    u_int x, y;

public:
    Matrix(u_int a, u_int b);
    Matrix(const Matrix &);
    ~Matrix();

    double det();

    Matrix& operator=(const Matrix &);

    Matrix operator+(const Matrix &) const;
    Matrix operator-(const Matrix &) const;                           
    Matrix operator*(const Matrix &) const;
    friend Matrix operator*(const Matrix &, const double &);
    Matrix operator/(const Matrix &) const;

    double* operator[](const u_int idx) const {
        return mtrx[idx];
        //or: return &mtrx[idx*x];
    }

    bool IsEqualSize(const Matrix &) const;
    u_int GetX() const { return x; }
    u_int GetY() const { return y; }
};

#endif
#include "Matrix.hpp"
#include <utility>
#include <stdexcept>

Matrix::Matrix(u_int a, u_int b)
    : x(a), y(b)
{
    mtrx = new double*[x];
    for (u_int i = 0; i < x; ++i) {
        mtrx[i] = new double[y];
    }

    // or: mtrx = new double[x*y];
}

Matrix::Matrix(const Matrix &ref)
    : x(ref.x), y(ref.y)
{
    mtrx = new double*[x];
    for (u_int i = 0; i < x; ++i) {
        mtrx[i] = new double[y];
        for (u_int j = 0; j < y; ++j) {
            mtrx[i][j] = ref.mtrx[i][j];
        }
    }

    /* or:
    u_int size = x*y;
    mtrx = new double[size];
    for (u_int i = 0; i < size; ++i) {
        mtrx[i] = ref.mtrx[i];
    }
    */
}

Matrix::~Matrix()
{
    // this loop is not needed for a 1D array...
    for (u_int i = 0; i < x; ++i) {
        delete[] mtrx[i];
    }

    delete[] mtrx;
}

bool Matrix::IsEqualSize(const Matrix &a) const
{
    return (a.GetX() == x) && (a.GetY() == y);
}

Matrix& Matrix::operator=(const Matrix &a)
{
    if (&a != this)
    {
        Matrix tmp(a);
        std::swap(mtrx, tmp.mtrx);
    }
    return *this;
}

Matrix Matrix::operator+(const Matrix &a) const
{
    if (!IsEqualSize(a))
        throw std::logic_error("Cannot add matrices of different sizes");

    Matrix matrix(x, y);

    for (u_int i = 0; i < x; ++i) {
        for (u_int j = 0; j < y; ++j)
            matrix.mtrx[i][j] = mtrx[i][j] + a.mtrx[i][j];
    }

    /* or:
    u_int size = x*y;
    for (u_int i = 0; i < size; ++i) {
        matrix.mtrx[i] = mtrx[i] + a.mtrx[i];
    }
    */

    return matrix;
}

...
#include <stdio.h>
#include "Matrix.hpp"

int main()
{
    Matrix a(2, 5);
    Matrix b(2, 5);

    for (u_int i = 0; i < a.GetX(); ++i)
    {
        for (u_int j = 0; j < a.GetY(); ++j)
        {
            a[i][j] = i + j;
        }
    }

    for (u_int i = 0; i < b.GetX(); ++i)
    {
        for (u_int j = 0; j < b.GetY(); ++j)
        {
            b[i][j] = i + j;
        }
    }

    Matrix c = a + b;

    return 0;
}