Создал класс, который реализует массив на shared_ptr. Хочу перегрузить операцию равно, внутри метода все работает - массив получает новый размер и новые указатели. Но когда происходит return, то в обїекте остается только размер, а shared_ptr становится empty. Вроде бы, мне нужно использовать shared_from_this, но мне не нужно возвращать указатели на мой массив, а объект. Как это исправить?
class DynamicArr: public std::enable_shared_from_this<DynamicArr<T>>
{
private:
int Size;
std::shared_ptr<T[]> arr;
public:
DynamicArr()
{
arr.reset(new T[1]);
arr[0] = 0;
}
DynamicArr(int Size)
{
this->Size = Size;
arr.reset(new T[Size]);
for (int i = 0; i < Size; arr[i++] = Size-i);
}
DynamicArr(DynamicArr<T> &obj)
{
this->Size = obj.Size;
arr = std::move(obj.arr);
}
~DynamicArr() {
arr.reset(new T[1]);
}
DynamicArr<T> operator= (const DynamicArr<T> &Arr2)
{
if (this != &Arr2)
{
this->Size = Arr2.Size;
this->arr = Arr2.arr;
return *this;
}
else
return *this;
}
При таком объявлении класса реализовывать эти функции вообще не надо. Все конструкторы копирования и перемещения, операторы копирования и перемещения, а также деструктор будут правильно сгенерированы компилятором. Умные указатели в том числе для того и предназначены, чтобы в таком классе можно было пользоваться Правилом Ноля.
Не ясно, зачем вы написали конструктор копирования, который на самом деле разрушает (перемещает) исходный объект - из-за него ваш код и ведет себя странно.
Также, почему ваш оператор присваивания возвращает результат "по значению", вместо традиционного возвращения ссылки?
В данном случае можно было явно не писать и конструктор по умолчанию. Но раз вам зачем-то захотелось выделять там массив размера 1
, то так тому и быть. Однако вы забыли там инициализировать Size
.
Причин для наследования от std::enable_shared_from_this
в вашем классе тоже не видно.
template <typename T>
class DynamicArr
{
private:
int Size;
std::shared_ptr<T[]> arr;
public:
DynamicArr() : Size(1), arr(new T[1]())
{}
DynamicArr(int Size) : Size(Size), arr(new T[Size])
{
for (int i = 0; i < Size; arr[i++] = Size-i);
}
};
Также arr[i++] = Size-i
. До C++17 это выражение вызывает неопределенное поведение. После С++17 правая часть оператора присваивания упорядочена перед левой. То есть ваш код заполняет массив значениями { Size, Size - 1, ..., 1 }
, а не { Size - 1, Size - 2, ..., 0 }
. Это именно то, что вы хотели? Это, кстати, не согласуется с тем, что делает конструктор по умолчанию (arr[0] = 0;
).
(Что интересно, в GCC поведение действительно меняется в зависимости от -std=c++17
)
Как я и предполагал, у вас неправильно реализован конструктор копирования - вместо копирования он выполняет перемещение указателя на массив из другого объекта. Соответственно при возвращении нового объекта из operator =
будет происходить перемещение указателя на массив из текущего объекта в возвращаемый. Для исправления необходимо реализовать нормальный конструктор копирования и ничего не возвращать из operator =
DynamicArr(DynamicArr<T> const & obj)
: Size{obj.Size}
: arr{obj.arr}
{
return;
}
void operator =(DynamicArr<T> const & obj)
{
if(this != ::std::addressof(Arr2))
{
this->Size = obj.Size;
this->arr = obj.arr;
}
return;
}
Спасибо пользователю AR Hovseypan, теперь объект возвращается правильно.
DynamicArr<T>& operator= (const DynamicArr<T> &Arr2)
{
if (this != &Arr2)
{
this->Size = Arr2.Size;
this->arr = Arr2.arr;
return *this;
}
else
return *this;
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Насколько мне известно, для типа int инициализировать статические константные члены можно внутри класса, не вынося определение вне класса:
Я делаю простейшую тудушечкуНужна помощь в реализации удаления выполненных задач