конструктор копирования — правило C ++ из пяти для класса с динамической памятью

Итак, я пишу большую пятерку для класса, который имеет динамический массив int

struct intSet {
int *data;
int size;
int capacity;

intSet();
~intSet();
intSet(const intSet& is);
intSet(intSet &&is);
intSet &operator=(const intSet& is);
intSet &operator=(intSet &&is);
}

Что я получил так далеко:

intSet::intSet(const intSet& is){
this->size=is.size;
this->capacity=is.capacity;
this->data=is.data;
}

intSet::intSet(intSet &&is){
this->size=is.size;
this->capacity=is.capacity;
this->data=is.data;
is.data=nullptr;
}

intSet& intSet::operator=(const intSet& is){
if(&is!=this){
size=is.size;
capacity=is.capacity;
delete [] data;
data=is.data;
data=new int[capacity];
for(int i=0;i<size;i++){
data[i]=is.data[i];
}
}
return *this;
}

intSet& intSet::operator=(intSet &&is){
if(&is!=this){
size=is.size;
capacity=is.size;
delete [] data;
data=is.data;
is.data=nullptr;
}
return *this;
}

intSet::~intSet(){
delete [] this->data;
}

Ясно, что с этим что-то не так, но я не очень знаком с большой пятеркой … Я много искал, но так и не нашел ответа …

0

Решение

Понятно, что с этим что-то не так … не нашел ответа …

Самый большой неправильно находится в конструкторе копирования.

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

Решение: вместо этого выделите новый массив. Другими словами: делайте глубокую копию, а не мелкую. Если вам нужна помощь в выяснении, как это сделать, просто взгляните на реализацию оператора присваивания копии (хотя вы можете упростить std::copy).

Оператор присваивания копии также имеет недостатки:

  • Есть лишний data=is.data;, что бессмысленно, так как data перезаписывается на следующей строке.
  • После того, как вы исправили конструктор копирования для выполнения глубокого копирования, как это делает оператор присваивания, оба они будут содержать дублированный код для выделения нового массива и копирования содержимого. Наличие дубликата кода немного плохо.
  • Оператор не дает строгой гарантии исключения. Если при выделении нового массива возникает исключение, указатель члена будет указывать на удаленный массив (ведущий к UB). Даже если распределение выполнено успешно, копирование содержимого может привести к исключению. Если это так, то частичное копирование не откатывается, и объект остается в несогласованном состоянии. Отсутствие сильной гарантии исключения умеренно плохо.

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


Лучшее решение: из того, что мало показано, ваш класс, кажется, заново изобретает std::vector, Вряд ли это когда-либо нужно. Просто использовать std::vector вместо.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]