Динамический массив ... конструктор копирования, деструктор, перегруженный оператор присваивания

Я готовлюсь к промежуточному экзамену. Возникает вопрос о динамической настройке массива и, возможно, о создании конструктора копирования, деструктора и перегрузке оператора присваивания. Не могли бы вы проверить, прав ли я. Также я не понимаю, что означает перегрузка оператора присваивания. Вы можете мне с этим помочь?

class A
{
int* myArray;   //basically I created a pointer called myArray, 
A()             //are my copy constructors correct? A(), and A(int size)?
{
    myArray = 0;
}
A(int size)
{
    myArray = new int[size];
}
~A()             // I think my destructor is correct
{
    delete [] myArray;
}

Можете ли вы проверить мой код, пожалуйста? Также как мне перегрузить оператор присваивания?

Заранее спасибо.

Ответов (5)

Решение

Конструктор копирования используется для создания объекта на основе другого экземпляра того же типа. У тебя такого нет. Вы можете определить его, используя такой код:

A(const A &other)
{
   myArray = new int[other._size];
   _size = other._size;
   memcpy(myArray, other.myArray, sizeof(int) * _size);
}

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

Перегруженный оператор присваивания должен выглядеть так:

const A &operator=(const A &other)
{
   if(this == &other) return *this; // handling of self assignment, thanks for your advice, arul.
   delete[] myArray; // freeing previously used memory
   myArray = new int[other._size];
   _size = other._size;
   memcpy(myArray, other.myArray, sizeof(int) * _size);
   return *this;
}

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

Частичный ответ: перегрузка функции предполагает создание разных версий этой функции, которые принимают разные числа или типы аргументов. Таким образом, перегрузка оператора присваивания повлечет за собой создание нескольких функций для оператора присваивания, которые позволят вам присваивать объекты различных типов переменной типа A .

Вы правильно определили 2 перегруженных конструктора и деструктор.

Однако вы неправильно определили явный конструктор копирования .

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

Проблема с автоматически сгенерированным конструктором неявной копии в вашем конкретном случае заключается в том, что он будет выполнять только неглубокую копию myArray , где он имеет то же значение указателя, но не выделил свой собственный раздел памяти для myArray.

Это означает, что если вы удалите myArray в исходном объекте, это повлияет на копию, что, скорее всего, не то, что вам нужно.

Определение явного конструктора копирования, подобного этому, поможет:

A(const A& copy)
  : _size(copy.size), myArray(new int[copy.size]) 
{
    // #include <algorithm> for std::copy
    std::copy(copy.data, copy.data + copy.size, data);
}

(Источник: скопировано из Википедии )

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

Изменить: Из этой статьи :

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

при работе с копией объекта и распределением динамической памяти рекомендуется использовать вспомогательную функцию подкачки

A(const A& other)
    : myArray(0)
    , _size(0)
{
   if(this != &other) {
      A my_tmp_a(other._size);
      std::copy(&other[0], &other[other._size], &my_tmp_a[0]);
      swap(my_tmp_a);
   }
}

const A& operator=(const A& other)
{
   if(this == &other) return *this;
   A my_tmp_a(other._size);
   std::copy(&other[0], &other[other._size], &my_tmp_a[0]); 
   swap(my_tmp_a);       
   return *this;
}

void swap(const A& other) {
   int* my_tmp_array = this.myArray;
   this.myArray = other.myArray;
   other.myArray = my_tmp_array;
   int my_tmp_size = this._size;
   this._size = other._size;
   other._size = my_tmp_size;
}

Убедитесь, что вы определили три функции, если хотите определить одну из них. Это называется правилом «все или ничего». Это: 1) конструктор копирования. 2) оператор присваивания. 3) деструктор.