C++ - 我的 move/copy 构造函数和 move/copy 赋值运算符有什么问题?

C++ - What is wrong with my move/copy constructors and move/copy assign operators?

所以我有自己的矩阵 class 并且我尝试为 class 重载 ++= 运算符,如下所示:

template <class T>
void Matrix<T>::operator+=(Matrix& mat) {
  if (this->m_rows != mat.m_rows || this->m_cols != mat.m_cols) {
    cerr << "Matrix rows/cols don't match" << endl;
  }
  else {
    for (unsigned int i = 0; i < this->m_rows; i++) {
      for (unsigned int j = 0; j < this->m_cols; j++) {
        this->m_vec[i * this->m_cols + j] += mat.m_vec[i * this->m_cols + j];
      }
    }
  }
}

template <class T>
Matrix<T> operator+(Matrix<T> mat1, Matrix<T>& mat2) {
  if (mat1.get_rows() != mat2.get_rows() || mat1.get_cols() != mat2.get_cols()) {
    cerr << "Matrix rows/cols don't match" << endl;
  }
  else {
    mat1 += mat2;
    return mat1;
  }
}

(我正在尝试使 + 运算符可链接,而 += 不可链接。矩阵由一维数组表示)

但是,当我尝试将两个矩阵相加时,程序拒绝相加(没有错误消息)。我怀疑我的 move/copy 构造函数、move/copy 赋值运算符或我的析构函数可能有问题,但我无法找出问题所在。

// Copy constructor
template <class T>
Matrix<T>::Matrix(Matrix& obj) {
  size_t rows = obj.get_rows();
  size_t cols = obj.get_cols();
  this->m_rows = rows;
  this->m_cols = cols;
  this->m_capacity = rows * cols;
  this->m_vec = new T[rows * cols];
  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
      this->m_vec[j + i * cols] = obj(i, j);
    }
  }
}

// Move constructor
template <class T>
Matrix<T>::Matrix(Matrix&& obj)
  : m_rows(0)
  , m_cols(0)
  , m_capacity(0)
  , m_vec(nullptr)
{
  m_rows = obj.get_rows();
  m_cols = obj.get_cols();
  m_capacity = obj.get_capacity();
  m_vec = obj.m_vec;

  obj.m_rows = 0;
  obj.m_cols = 0;
  obj.m_capacity = 0;
  obj.m_vec = nullptr;
}

// Destructor
template <class T>
Matrix<T>::~Matrix() {
  delete[] m_vec;
}

// Copy assignment operator
template <class T>
Matrix<T>& Matrix<T>::operator=(const Matrix& obj)
{
  m_rows = obj.get_rows();
  m_cols = obj.get_cols();
  m_capacity = obj.get_capacity();
  m_vec = obj.m_vec;
  return *this;

}

// Move assignment operator
template <class T>
Matrix<T>& Matrix<T>::operator=(Matrix&& obj)
{
  if (this != &obj)
  {
    delete[] m_vec;
    m_rows = obj.get_rows();
    m_cols = obj.get_cols();
    m_capacity = obj.get_capacity();
    m_vec = obj.m_vec;

    obj.m_rows = 0;
    obj.m_cols = 0;
    obj.m_capacity = 0;
    obj.m_vec = nullptr;
  }
  return *this;
}

// Matrix class properties
class Matrix{
private:
  size_t m_rows;
  size_t m_cols;
  size_t m_capacity;
  T* m_vec;
}

我是 C++ 的新手,这是我第一次尝试创建 copy/move constructors/assignment 运算符,因此我可能遗漏了一些明显的东西。也许我什至把这个复杂化了。是否有 easier/better 方法来编写 move/copy 构造函数和赋值运算符?你能在这里发现什么奇怪的东西吗?我觉得还不错...

谢谢!

编辑: 我现在已尝试按照@eerorika 的建议更改复制赋值运算符,但我的 ++= 运算符仍然不起作用(与以前相同)。可以肯定的是,然后我还尝试以与编辑复制赋值运算符相同的方式编辑我的移动赋值运算符和移动构造函数,但仍然......没有。这是编辑后的版本

// Move constructor
template <class T>
Matrix<T>::Matrix(Matrix&& obj)
  : m_rows(0)
  , m_cols(0)
  , m_capacity(0)
  , m_vec(nullptr)
{
  this->m_rows = obj.get_rows();
  this->m_cols = obj.get_cols();
  this->m_capacity = obj.get_capacity();
  //m_vec = obj.m_vec;
  this->m_vec = new T[obj.get_rows() * obj.get_cols()];
  for (int i = 0; i < obj.get_rows(); i++) {
    for (int j = 0; j < obj.get_cols(); j++) {
      this->m_vec[j + i * obj.get_cols()] = obj.m_vec[i * this->m_cols + j];
    }
  }

  obj.m_rows = 0;
  obj.m_cols = 0;
  obj.m_capacity = 0;
  obj.m_vec = nullptr;
}

// Move assigment operator
template <class T>
Matrix<T>& Matrix<T>::operator=(Matrix&& obj)
{
  // If the address of the object being passed in is the same as "this", do nothing.
  if (this != &obj)
  {
    delete[] m_vec;
    this->m_rows = obj.get_rows();
    this->m_cols = obj.get_cols();
    this->m_capacity = obj.get_capacity();
    //m_vec = obj.m_vec;
    this->m_vec = new T[obj.get_rows() * obj.get_cols()];
    for (int i = 0; i < obj.get_rows(); i++) {
      for (int j = 0; j < obj.get_cols(); j++) {
        this->m_vec[j + i * obj.get_cols()] = obj.m_vec[i * this->m_cols + j];
      }
    }

    obj.m_rows = 0;
    obj.m_cols = 0;
    obj.m_capacity = 0;
    obj.m_vec = nullptr;
  }
  return *this;
}

// Copy assignment operator
template <class T>
Matrix<T>& Matrix<T>::operator=(Matrix& obj)
{
  this->m_rows = obj.get_rows();
  this->m_cols = obj.get_cols();
  this->m_capacity = obj.get_capacity();
  //m_vec = obj.m_vec;
  this->m_vec = new T[obj.get_rows() * obj.get_cols()];
  for (int i = 0; i < obj.get_rows(); i++) {
    for (int j = 0; j < obj.get_cols(); j++) {
      this->m_vec[j + i * obj.get_cols()] = obj.m_vec[i * this->m_cols + j];
    }
  }
  return *this;
}

知道现在可能出了什么问题吗?您确定我的 ++= 运算符中的代码没有问题吗?帮助。

编辑 2:

应@numzero 的要求,我将为 operator()

添加代码
template <class T>
T& Matrix<T>::operator()(unsigned int row, unsigned int col) {
  if (row > this->m_rows || col > this->m_cols) {
    cerr << "index out of range" << endl;;
  }
  return this->m_vec[(row - 1) * m_cols + (col - 1)];
}

您的复制赋值运算符复制 m_vec 指针,而不是复制其内容(就像复制构造函数那样)。

What is wrong with my move/copy constructors and move/**** assign operators?

据我所知,没有什么严重的。一个小问题是您不必要地分配了可以直接在成员初始化列表中使用这些值初始化的成员。

What is wrong with my copy assign operators?

您的析构函数删除成员指针。因此,您必须维护 class 不变量,即 class 的每个实例都具有指针的唯一所有权,即没有其他实例具有相同的指针值。否则,各个对象的析构函数将尝试删除导致未定义行为的相同指针。

您的复制赋值运算符复制了违反 class 不变量的指针。请参阅您的复制构造函数以获取您应该执行的操作的示例。


额外建议:永远不要像您在这里那样使用拥有裸指针。请改用智能指针或 RAII 容器,例如 std::vector