T *_vec;
std::size_t _l;
Это проблемный дизайн! Я не говорю, что это неправильно само по себе, но тогда вам нужно правильно управлять памятью самостоятельно. Игнорирование правила трех (пяти) очень опасно в этом отношении. У вас есть указатель на (потенциально?) Динамически распределенную память, поэтому должен быть некоторый экземпляр, который отвечает за его удаление (не обязательно должен быть ваш RowVector
, но что еще тогда?).
С чисто технической точки зрения, вы даже можете позволить _vec указывать на данные какого-либо вектора, при условии вы гарантируете, что этот другой вектор будет существовать столько, сколько вы хотите получить доступ к данным через указатель & Ndash; что в целом требует, однако, довольно определенных усилий.
Самым безопасным было бы, чтобы каждая строка поддерживала свои собственные данные, копируя (или перемещая) их из другого вектора. Тогда проще всего сохранить данные в отдельном std::vector
(заменив необработанный указатель).
Если вы хотите избежать копирования данных и вместо этого обмениваться данными между различными матрицами и их строками, то вы можете поддерживать данные через std::shared_ptr
- либо поддерживая необработанный массив, либо, возможно, даже кучу -распределенный std::vector
.
Если вы выберете std::vector
или std::shared_ptr
, тогда конструкторы копирования и перемещения и операторы присваивания станут совершенно простыми:
class C
{
public:
C(C const&) = default;
C(C&&) = default;
C& operator= (C const&) = default;
C& operator= (C&&) = default;
};
Все эти значения по умолчанию будут выполнять копирование / перемещение в соответствии с элементом, и в std::vector
и std::shared_ptr
уже есть соответствующие конструкторы и операторы, так что вы будете в порядке & ndash; и теперь вы можете нарушить правило пяти, отбросив деструктор, так как достаточно стандартного (вызывающего все деструкторы члена).
Если вы рассматриваете общие указатели: имейте в виду, что затем вы не можете назначить данные std::vector
для: std::vector
выполняет свое собственное управление памятью, и в результате вы получите двойное удаление, поэтому в данном конкретном случае вам все равно придется создать копию. Вы можете оказаться в нескольких конструкторах и операторах присваивания:
std::shared_ptr<std::vector<int>> _data;
// assign shared pointers
RowVector(RowVector const&) = default;
RowVector(RowVector&&) = default;
// need to create copies of: we never know about the scope of the vector passed!
RowVector(std::vector<int> const& data) : _data(new std::vector<int>(data)) { }
RowVector(std::vector<int>&& data) : _data(new std::vector<int>(std::move(data))) { }
// we *are* sharing already -> no need to copy:
RowVector(std::shared_ptr<std::vector<int>& data) : _data(data) { }
Операторы присваивания аналогично.
Примечание: если вы хотите иметь математическую матрицу nxm, вы наверняка не хотите иметь зубчатый массив. Я бы предположил, что ваш Matrix
class 'конструктор уже создает соответствующий вектор векторов, тогда для присваивания вам еще нужно проверить длину:
// defaults not suitable any more!
RowVector& RowVector::operator=(RowVector const& other)
{
// still assuming shared pointer:
// (for vector, replace -> with .)
if(other._data->size() != _data.size())
{
throw SomeException();
}
_data = other._data;
}
RowVector(RowVector&& other)
{
if(other._data->size() != _data.size())
{
throw SomeException();
}
_data = std::move(other._data);
}