Что не так с моими конструкторами перемещения / копирования и операторами назначения перемещения / копирования? - PullRequest
0 голосов
/ 09 марта 2020

Итак, у меня есть свой собственный класс матрицы, и я попытался перегрузить операторы + и += для этого класса следующим образом:

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;
  }
}

(я пытаюсь сделать + оператор цепочки и += (не цепочка. Матрица представлена ​​одномерным массивом)

Однако, когда я пытаюсь добавить две матрицы, программа отказывается добавлять их (сообщение об ошибке отсутствует). Я подозреваю, что может быть что-то не так с моими конструкторами перемещения / копирования, операторами назначения перемещения / копирования или моим деструктором, но я не могу понять, что не так.

// 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 ++, и я впервые пытаюсь создать конструкторы / операторы копирования / перемещения, поэтому может быть что-то очевидное, чего мне не хватает. Может быть, я даже усложняю это. Есть ли более простой / лучший способ написать конструкторы перемещения / копирования и операторы присваивания? Вы можете заметить здесь что-нибудь странное? Мне кажется, это нормально ...

Спасибо!

РЕДАКТИРОВАТЬ: я сейчас попытался изменить оператор назначения копирования, как это предложено @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)];
}

Ответы [ 2 ]

4 голосов
/ 09 марта 2020

Что не так с моими конструкторами перемещения / копирования и оператором присваивания перемещения / **** s ?

Насколько я могу судить, ничего серьезного. Одна небольшая проблема заключается в том, что вы излишне назначаете элементы, которые могли инициализироваться этими значениями, непосредственно в списке инициализаторов элементов.

Что не так с моим копировать назначить оператор s ?

Ваш деструктор удаляет указатель члена. Из-за этого вы должны поддерживать инвариант класса, чтобы каждый экземпляр класса имел уникальное владение указателем, т.е. ни один другой экземпляр не имеет такого же значения указателя. В противном случае деструктор соответствующих объектов попытается удалить тот же указатель, что приведет к неопределенному поведению.

Ваш оператор копирования копии копирует указатель, который нарушает инвариант этого класса. См. Ваш конструктор копирования для примера того, что вы должны делать вместо этого.


Бонусный совет: никогда не используйте собственные голые указатели, как здесь. Вместо этого используйте умные указатели или контейнеры RAII, такие как std::vector.

1 голос
/ 09 марта 2020

Оператор присваивания копии копирует указатель m_vec вместо копирования его содержимого (как это делает конструктор копирования).

...