diff --git a/matrix.hpp b/matrix.hpp index cf39055cd246afc15abcfac1ebf3e212c356e929..632d23b2ea7efab42ddf79bbadd6485ca7eb331a 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -62,6 +62,7 @@ namespace linalg { // Деструктор ~Matrix() noexcept; + // Шаблонный оператор присваивания для матриц разных типов template<typename U> Matrix &operator=(const Matrix<U> &other); @@ -70,6 +71,8 @@ namespace linalg { template<typename U> Matrix &operator=(Matrix<U> &&other) noexcept; + size_t size() const noexcept { return m_rows * m_columns; } + private: // Указатель РЅР° данные матрицы @@ -85,4 +88,209 @@ namespace linalg { template<typename U> void free(U *&ptr, size_t n) noexcept; }; -} + + template<typename T> +// Функция swap для обмена РґРІСѓС… матриц местами (реализует семантику перемещения) + void swap(Matrix<T> &first, Matrix<T> &second) noexcept { first.swap(second); } + +// Конструктор для создания матрицы СЃ заданным количеством строк (РїРѕ умолчанию 1 столбец) + template<typename T> + Matrix<T>::Matrix(size_t rows) : m_rows(rows), m_columns(1), m_capacity(rows) { + // Выделяем память для элементов матрицы + m_ptr = reinterpret_cast<T *>(new std::byte[m_capacity * sizeof(T)]); + + size_t i = 0; + + try { + // Рнициализируем элементы матрицы значениями РїРѕ умолчанию + for (; i < rows; ++i) { + new(m_ptr + i) T(); + } + } catch (...) { + // Освобождаем память РІ случае исключения + free<T>(m_ptr, i + 1); + this->~Matrix(); + throw; + } + } + +// Конструктор для создания матрицы СЃ заданным количеством строк Рё столбцов + template<typename T> + Matrix<T>::Matrix(size_t rows, size_t columns): m_rows(rows), m_columns(columns), m_capacity(rows * columns) { + // Выделяем память для элементов матрицы + m_ptr = reinterpret_cast<T *>(new std::byte[m_capacity * sizeof(T)]); + + size_t i = 0; + + try { + // Рнициализируем элементы матрицы значениями РїРѕ умолчанию + for (; i < rows * columns; ++i) { + new(m_ptr + i) T(); + } + } catch (...) { + // Освобождаем память РІ случае исключения + free<T>(m_ptr, i + 1); + this->~Matrix(); + throw; + } + } + +// Конструктор копирования для создания матрицы РёР· РґСЂСѓРіРѕР№ матрицы РґСЂСѓРіРѕРіРѕ типа + template<typename T> + template<typename U> + Matrix<T>::Matrix(const Matrix<U> &other) : m_rows(other.m_rows), m_columns(other.m_columns), + m_capacity(m_rows * m_columns) { + // Выделяем память для РЅРѕРІРѕР№ матрицы + m_ptr = reinterpret_cast<T *>(new std::byte[m_capacity * sizeof(T)]); + + size_t i = 0; + + try { + // Копируем элементы РёР· РґСЂСѓРіРѕР№ матрицы + for (; i < m_rows * m_columns; ++i) { + new(m_ptr + i) T((other.m_ptr[i])); + } + } catch (...) { + // Освобождаем память РІ случае исключения + free<T>(m_ptr, i + 1); + this->~Matrix(); + throw; + } + } + +// Перемещающий конструктор для создания матрицы РёР· РґСЂСѓРіРѕР№ матрицы, переданной РїРѕ rvalue-ссылке + template<typename T> + template<typename U> + Matrix<T>::Matrix(Matrix<U> &&other) noexcept : m_ptr(reinterpret_cast<T *>(other.m_ptr)), m_rows(other.m_rows), + m_columns(other.m_columns), m_capacity(other.m_capacity) { + // Обнуляем РёСЃС…РѕРґРЅСѓСЋ матрицу, чтобы РѕРЅР° РЅРµ владела ресурсами + other.m_ptr = nullptr; + other.m_columns = other.m_rows = other.m_capacity = 0; + } + +// Конструктор инициализации РёР· одномерного СЃРїРёСЃРєР° значений + template<typename T> + template<typename U> + Matrix<T>::Matrix(std::initializer_list<U> lst) : m_rows(lst.size()), m_columns(1), m_capacity(lst.size()) { + // Выделяем память для элементов матрицы + m_ptr = reinterpret_cast<T *>(new std::byte[m_capacity * sizeof(T)]); + + size_t i = 0; + + try { + auto iter = lst.begin(); + // Копируем значения РёР· СЃРїРёСЃРєР° + for (; i < lst.size(); ++i) { + new(m_ptr + i) T(*iter); + ++iter; + } + } catch (...) { + // Освобождаем память РІ случае исключения + free<T>(m_ptr, i + 1); + this->~Matrix(); + throw; + } + } + +// Конструктор инициализации РёР· двумерного СЃРїРёСЃРєР° значений + template<typename T> + template<typename U> + Matrix<T>::Matrix(std::initializer_list<std::initializer_list<U>> lst) : m_rows(lst.size()), + m_columns(lst.begin()->size()), + m_capacity(m_rows * m_columns) { + // Выделяем память для элементов матрицы + m_ptr = reinterpret_cast<T *>(new std::byte[m_capacity * sizeof(T)]); + + size_t i = 0; + + try { + // Копируем значения РёР· двумерного СЃРїРёСЃРєР° + for (const auto &row : lst) { + for (auto &elem : row) { + new(m_ptr + i) T(elem); + ++i; + } + } + } catch (...) { + // Освобождаем память РІ случае исключения + free<T>(m_ptr, i + 1); + this->~Matrix(); + throw; + } + } + +// Деструктор матрицы для освобождения ресурсов + template<typename T> + Matrix<T>::~Matrix() noexcept { + if (m_ptr != nullptr) { + // Освобождаем память для всех элементов матрицы + free<T>(m_ptr, size()); + } + } + +// Оператор копирующего присваивания для матриц разных типов + template<typename T> + template<typename U> + Matrix<T> &Matrix<T>::operator=(const Matrix<U> &other) { + if (&other == this) { + return *this; + } + + // Если емкость текущей матрицы позволяет, обновляем существующие элементы + if (m_capacity >= other.size()) { + try { + for (size_t i = 0; i < size(); ++i) { + m_ptr[i] = other.m_ptr[i]; + } + for (size_t i = size(); i < other.size(); ++i) { + new(m_ptr + i) T(other.m_ptr[i]); + } + } catch (...) { + throw; + } + for (size_t i = other.size(); i < size(); ++i) { + (m_ptr + i)->~T(); + } + m_columns = other.m_columns; + m_rows = other.m_rows; + m_capacity = size(); + return *this; + } + + // Если емкость недостаточна, создаем РєРѕРїРёСЋ матрицы Рё обмениваемся ресурсами + try { + Matrix<T> copy(other); + ::linalg::swap(copy, *this); + } catch (...) { + throw; + } + + return *this; + } + +// Оператор перемещающего присваивания для матриц разных типов + template<typename T> + template<typename U> + Matrix<T> &Matrix<T>::operator=(Matrix<U> &&other) noexcept { + if (&other == this) { + return *this; + } + + // Уничтожаем текущие элементы матрицы + for (size_t i = 0; i < size(); ++i) { + (m_ptr + i)->~T(); + } + + // Освобождаем выделенную память + delete[] reinterpret_cast<std::byte *>(m_ptr); + m_rows = other.m_rows; + m_columns = other.m_columns; + m_ptr = reinterpret_cast<T *>(other.m_ptr); + + // Обнуляем РґСЂСѓРіСѓСЋ матрицу + other.m_ptr = nullptr; + other.m_columns = other.m_rows = 0; + + return *this; + } +} \ No newline at end of file