Реализация собственного класса Matrix
Создаю свой класс Matrix(использовать контейнеры STL нельзя, все ресурсы управляются вручную). Начал реализовать конструктор и оператор перемещения, но начинают появляться сомнения, что ушел в какую то не ту сторону. Можно узнать как можно сделать данные конструкторы и операторы наиболее эффективными с точки зрения памяти и времени выполнения?
Сам класс Matrix:
template <typename T>
class Matrix
{
private:
T *data = nullptr;
size_t rows;
size_t cols;
Конструктор и оператор:
Matrix(Matrix &&other) noexcept : rows((other.rows)), cols((other.cols)), data(other.data)
{
other.data = nullptr;
other.rows = 0;
other.cols = 0;
}
Matrix &operator=(Matrix<T> &&other) noexcept
{
if (&other == this)
{
return *this;
}
if (rows != other.rows || cols != other.cols)
{
std::cout << "Ошибка присваивания матриц разного размеры" << std::endl;
exit(-1);
}
clean();
std::swap(data, other.data);
std::swap(rows, other.rows);
std::swap(cols, other.cols);
other.data = nullptr;
other.rows = 0;
other.cols = 0;
return *this;
}
Функция очистки:
void clean()
{
if (nullptr != data)
{
rows = 0;
cols = 0;
delete[] data;
}
}
Ответы (1 шт):
Премещающий конструктор сделан нормально, но непонятно зачем там двойные скобки.
Еще есть более выпендрежный способ записать то же самое: : rows(std::exchange(other.rows, 0)). Тогда отдельное зануление в теле конструктора не нужно.
В перемещающем присваивании проверка на совпадение размеров смотрится очень странно, я бы убрал. swap тоже смотрится странно; раз вы все равно зануляете поле, можно обойтись rows = other.rows; other.rows = 0;.
Есть трюк, позволяющий в 99% случаев писать присваивание не думая, называется copy & swap idiom. Пишется так:
Matrix &operator=(Matrix<T> other) noexcept
{
std::swap(data, other.data);
std::swap(rows, other.rows);
std::swap(cols, other.cols);
return *this;
}
Прелесть в том, то он может одновременно работать как копирующий (если есть копирующий конструктор) и как перемещающий (если есть перемещающий конструктор). При такой записи проверка на самоприсваивание больше не нужна, и бросок исключения из копирующего/перемещающего конструктора не оставляет класс в неправильном состоянии.
В clear() забыли занулить указатель.
В низкоуровневых классах а-ля "матрица" не стоит печатать ничего в консоль и/или закрывать программу. Об ошибке лучше сообщать броском исключения, или возвращаемым значением функции (для operator= последнее не подойдет), или чем-то таким.