Я нарушаю Правило трех? - PullRequest
3 голосов
/ 04 февраля 2012

Я недавно прочитал, Правило трех , и мне интересно, нарушаю ли я его?

В моем приложении с графическим интерфейсом, такие классы, как MainFrame, Interface, Circuit,Breadboard и т. Д. (Имена классов являются ориентировочными) имеют по одному экземпляру каждого из них.В их конструкторах я выделил некоторые ресурсы (память), которые я благополучно высвобождаю в их деструкторах.

Поэтому я определил только деструктор , но не конструктор копирования и оператор присваивания .

Я уверен, что они мне не нужны, но мне любопытно, нарушаю ли я это правило, и что я могу / должен сделать, чтобы следовать ему?

Ответы [ 5 ]

6 голосов
/ 04 февраля 2012

Правило трех: имеет дело со всей Большой Тройкой, но это не обязательно означает, что вам придется определять их, если вы этого не хотите.Либо вы предоставляете их, либо запрещаете их.Чего не следует делать, так это игнорировать их.


Итак, я определил только деструктор, но не конструктор копирования и оператор копирования.
Нарушаю ли я Правило трех?

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

Это проблема?

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

В C ++ 11вместо этого вы можете использовать синтаксис = delete:

T(T const&) = delete; // no copy constructor
T& operator=(T const&) = delete; // no copy assignment
2 голосов
/ 04 февраля 2012

Это во многом зависит от логики вашего приложения и от того, как вы задокументировали классы интерфейса для пользователей.

Обычно хороший программист на С ++ должен знать правило трех (с половиной, если вы знаете «идиома копирования и обмена») и 5 ​​с 1/2 в случае с ++ 11 (семантика перемещения).

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

Но если вы всегда играете за свой класс, передавая их как REFERENCE, тогда лучше определить ctor и оператор присваивания по умолчанию как private, чтобы даже если вы передаете по valy или по ошибке копируете, компилятор предупредит вас.

2 голосов
/ 04 февраля 2012

Вы должны объявить (но не реализовать) частный конструктор копирования и оператор присваивания.Убедитесь, что вы не реализуете функции.Это предотвратит любое копирование классов, которые не должны копироваться.

1 голос
/ 04 февраля 2012

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

Если вы также делаете освобождение, вам понадобится конструктор копированияи операторы присваивания.Представьте, что у вас есть класс с указателем на что-то:

struct Foo
{
    Foo() { ptr_ = new int; }
    ~Foo() { delete ptr_; }
    int* ptr_;
};

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

Foo(cont Foo& other) {
    other.ptr_ = new int(*ptr_);
}

// Same for operator=

Если вы не выполняете никаких динамических распределений в конструкторе / деструкторе, есть хороший шансвам на самом деле не нужен конструктор копирования или оператор присваивания (но не обязательно).

1 голос
/ 04 февраля 2012

Да, это нарушает правило трех согласно этому определению.

Это, однако, «правило большого пальца». Общее руководство. Если вам не нужны операции копирования или назначения, не выполняйте их. Другие предложили объявить их частными и определить их как пустые. Я бы пошел еще дальше и сказал, что даже не определяю их.

Если вы определите их, то потенциально можете по-прежнему вызывать пустые методы. Вместо этого оставьте их неопределенными, и, если вы когда-нибудь попытаетесь вызвать эти методы, вы получите ошибку компоновщика, потому что определения методов не найдены. Избегайте ошибок во время сборки по сравнению с ошибками во время выполнения / нежелательным поведением.

...