【问题标题】:C++ Matrix Operator+C++ 矩阵运算符+
【发布时间】:2020-04-03 05:09:41
【问题描述】:

程序matrix.cc的方法template <class T> const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const应该能够将调用对象的矩阵和rhs的矩阵之和作为新对象返回。此外,lhs 和 rhs 的行和列将相等。

我从编译器收到的错误输出是:

[hw7] make clean && make bin/test_add && ./bin/test_add                                           UserSettings  ✱
rm -f bin/*
g++   -std=c++11   -Wall       -I inc   -I src   -c   src/test_matrix_add.cc -o bin/test_matrix_add.o
g++   -std=c++11   -Wall       -I inc   -I src   -o   bin/test_add bin/test_matrix_add.o
Testing Matrix::operator+
  Expected Matrix2[0][0]: 3.0, Actual: 1
  FAILED

当我知道我通过了// TEST MUL ASSIGMENT OP CORRECT RETURN 部分时,有人可以告诉我为什么会收到此“失败”输出。

这是我的matrix.cc:

#include <matrix.h>

template <class T>
Matrix<T>::Matrix() {
  rows_ = 0;
  cols_ = 0;
  m_ = nullptr;
}

template <class T>
Matrix<T>::Matrix(unsigned int rows, unsigned int cols)
    : rows_(rows), cols_(cols) {
  m_ = new T *[rows_];
  for (unsigned int i = 0; i < rows_; ++i) {
    m_[i] = new T[cols_];
  }
}

template <class T>
Matrix<T>::Matrix(const Matrix<T> &that) {
  rows_ = that.rows_;
  cols_ = that.cols_;
  m_ = new T *[rows_];
  for (unsigned int i = 0; i < rows_; ++i) {
    m_[i] = new T[cols_];
    for (unsigned int j = 0; j < cols_; ++j) {
      m_[i][j] = that.m_[i][j];
    }
  }
}

template <class T>
Matrix<T>::~Matrix() {
  for (unsigned int i = 0; i < rows_; ++i) {
    delete[] m_[i];  // delete columns
  }
  delete[] m_;  // delete columns
}

template <class T>
T Matrix<T>::Get(unsigned int row, unsigned int col) const {
  if (row > rows_ && col > cols_) {
    throw std::out_of_range("error: index out of range");
  }
  return this->m_[row][col];
}

template <class T>
const Matrix<T> &Matrix<T>::operator=(const Matrix<T> &rhs) {
  if (this == &rhs) {
    return *this;
  }  // returns the address

  for (unsigned int i = 0; i < rows_; ++i) {
    delete[] m_[i];
  }
  delete[] m_;

  rows_ = rhs.rows_;
  cols_ = rhs.cols_;
  m_ = new T *[rows_];
  for (unsigned int i = 0; i < rows_; ++i) {
    m_[i] = new T[cols_];
    for (unsigned int j = 0; j < cols_; ++j) {
      m_[i][j] = rhs.m_[i][j];
    }
  }
  return *this;
}

template <class T>
const Matrix<T> &Matrix<T>::operator*=(T rhs) {
  for (unsigned int i = 0; i < rows_; ++i) {
    for (unsigned int j = 0; j < cols_; ++j) {
      m_[i][j] *= rhs;
    }
  }
  return *this;
}

template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T> &rhs) const {
  if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_)) {
    std::cout << "Cannont add matrices. Wrong dimensions\n";
    exit(0);
  }
  Matrix<T> lhs;
  lhs.rows_ = this->rows_;
  lhs.cols_ = this->cols_;
  for (unsigned int i = 0; i < lhs.rows_; ++i) {
    for (unsigned int j = 0; j < lhs.cols_; ++j) {
      lhs[i][j] += rhs[i][j];
    }
  }
  return lhs;
}

这是我的matrix.h:

#include <cassert>
// using assert
#include <exception>
#include <iostream>

template <class T>
class Matrix {
 public:
  friend class MatrixTester;

  Matrix();  // for testing, useless in practice
  Matrix(unsigned int rows, unsigned int cols);
  Matrix(const Matrix<T> &that);
  ~Matrix();
  T Get(unsigned int row, unsigned int col) const;
  const Matrix<T> &operator=(const Matrix<T> &rhs);
  const Matrix<T> &operator*=(T rhs);
  const Matrix<T> operator+(const Matrix<T> &rhs) const;

 private:
  T **m_;
  unsigned int rows_;
  unsigned int cols_;
};

#include <matrix.cc>  //NOLINT

这是我的 test_matrix_add.cc 测试仪:

#include <test_matrix.h>

int main(int argc, char** argv) {
  MatrixTester tester;

  cout << "Testing Matrix::operator+" << endl;
  if (tester.Test_AddOp()) {
    cout << "  PASSED" << endl;
    return 0;
  }

  cout << "  FAILED" << endl;
  return 1;
}

bool MatrixTester::Test_AddOp() const {
  const int kRows = 4, kCols = 5;
  Matrix<double> m1;
  m1.m_ = new double*[kRows];
  for (unsigned int i = 0; i < kRows; ++i) {
    m1.m_[i] = new double[kCols];

    for (unsigned int j = 0; j < kCols; ++j)
      m1.m_[i][j] = (i + 1.0) * (j + 1.0);
  }
  m1.rows_ = kRows;
  m1.cols_ = kCols;

  // TEST ADDITION CORRECTNESS
  Matrix<double> m2;
  m2 = m1;
  // + m1 + m1;
  if (m2.m_[0][0] != 3) {
    cout << "  Expected Matrix2[0][0]: 3.0, Actual: " << m2.m_[0][0] << endl;
    return false;
  }
  if (m2.m_[1][3] != 24.0) {
    cout << "  Expected Matrix2[1][3]: 24.0, Actual: " << m2.m_[1][3] << endl;
    return false;
  }
  if (m2.m_[2][2] != 27.0) {
    cout << "  Expected Matrix2[2][2]: 27.0, Actual: " << m2.m_[2][2] << endl;
    return false;
  }
  if (m2.m_[3][4] != 60.0) {
    cout << "  Expected Matrix2[2][2]: 60.0, Actual: " << m2.m_[2][2] << endl;
    return false;
  }

  return true;
}

【问题讨论】:

  • lhs 不是加法的左侧。它应该是添加的 result,即返回的对象(请参阅您的 return 语句)。建议你改名。添加的左侧是this。现在考虑需要将哪些值相加以及需要将结果存储在哪里。目前您正在添加lhs(结果)和rhs(右侧)并将结果存储在lhs(结果)中:lhs[i][j] += rhs[i][j];。你觉得这对吗?
  • 可能有意义的是,您将lhs 视为左侧运算符的副本。但这需要您将其实际构建为 *this 的副本。
  • 已发布的matrix.h 包括matrix.cc,其中包括matrix.h。你的真实代码中是否包含守卫?
  • @Bob__ 是的,我确实有包括警卫。

标签: c++ matrix dynamic-memory-allocation addition


【解决方案1】:

首先,这里的代码太多了。

为了解决您的问题,我看不到您将内存分配给lhs.m_。这是一个问题,因为您使用默认构造函数初始化 lhs,该构造函数仅将 this-&gt;m_ 分配给 nullptr

要解决这个问题,这应该可以工作(尽管未经测试):

template <class T>
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& rhs) const
{
    if (!(this->cols_ == rhs.cols_) || (this->rows_ == rhs.rows_))
    {
        std::cout << "Cannot add matrices. Wrong dimensions\n";
        exit(0);
    }
    Matrix<T> lhs;
    lhs.rows_ = this->rows_;
    lhs.cols_ = this->cols_;

    // Allocate memory for `lhs.m_`, like you did in your 2nd constructor
    lhs.m_ = new T* [rows_];
    for (unsigned i = 0; i < rows_; ++i)
    {
        m_[i] = new T[cols_];
    }
    // [End] allocation

    for (unsigned int i = 0; i < lhs.rows_; ++i)
    {
        for (unsigned int j = 0; j < lhs.cols_; ++j)
        {
            lhs[i][j] += rhs[i][j];
        }
    }
    return lhs;
}

此外,有些无关紧要,请注意始终将m_ 视为双指针。我没有阅读您的所有代码,但请小心。还要记住,您必须在析构函数中释放 all 使用 new 分配的内存。就个人而言,我认为您应该使用来自&lt;memory&gt; 的智能指针(例如std::unique_ptr 等),您可以了解更多关于here 的信息。使用智能指针将使指针自行释放内存,您不必担心内存泄漏。

编辑 1
正如胡桃所说,更好的解决方案是调用第二个构造函数,它将为您分配内存。因此,您修改后的功能将是:

template <class T>
/**
 Note:
   > When you call this function (e.g. Matrix<T> new_mat = mat1 + mat2),
     `mat1` is `this` and `mat2` is what you're calling `rhs`. I've done
     some renaming and corrected your logic errors here
*/
const Matrix<T> Matrix<T>::operator+(const Matrix<T>& other) const
{
    if (!(this->cols_ == other.cols_) || (this->rows_ == other.rows_))
    {
        std::cout << "Cannot add matrices. Wrong dimensions\n";
        exit(0);
    }

    // Call the 2nd constructor
    Matrix<T> res(this->rows_, this->cols_);

    for (unsigned i = 0; i < res.rows_; ++i)
    {
        for (unsigned j = 0; j < res.cols_; ++j)
        {
            res.m_[i][j] = this->m_[i][j] + other.m_[i][j];
        }
    }
    return res;
}



编辑 2
根据@walnut 的评论,上面的代码正确地添加了矩阵。

【讨论】:

  • @walnut 哦,是的,我只是想修复最明显的错误。我会回去再修改一遍lol
  • 我对这篇文章的另一个问题是:添加测试器文件是否正确?它是否正确调用了两个矩阵的加法运算符?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多