0

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

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; 
} 

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

+2

Вы имеете в виду «Правило пяти»: http://en.cppreference.com/w/cpp/language/rule_of_three –

+1

Ваш экземпляр копии делает мелкую копию, но ваш оператор присваивания копий делает глубокую копию. Кроме того, используйте список инициализаторов конструктора, это не Java. – user2296177

+0

@BryanChen, так что большая пятерка - это конструктор копирования, назначение копии, перемещение конструктора, назначение перемещения. – anddn

ответ

2

Ясно, что есть что-то неправильно с ним ... не найти ответ ...

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

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

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

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

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

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


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

Смежные вопросы