Подтвердить что ты не робот

В каких обстоятельствах я должен предоставить оператора присваивания, конструктора копирования и деструктора для моего класса С++?

Скажем, у меня есть класс, где единственный член данных - это что-то вроде std::string или std::vector. Должен ли я предоставить команду "Копировать конструктор", "Деструктор" и "Назначение"?

4b9b3361

Ответ 1

Если ваш класс содержит только векторные/строковые объекты в качестве своих членов данных, вам не нужно их реализовывать. Классы С++ STL (например, vector, string) имеют собственный экземпляр ctor, перегруженный оператор присваивания и деструктор.

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

Ответ 2

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

Однако не все классы нуждаются в них. Если в классе нет ресурсов (в частности, памяти), с ними все будет в порядке. Например, класс с единственным компонентом string или vector им действительно не нужен - если вам не требуется какое-то специальное поведение при копировании (по умолчанию будет только скопировать элементы).

Ответ 3

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

Ответ 4

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

По моему опыту, всегда лучше определить их самостоятельно и привыкнуть к тому, чтобы они поддерживались при изменении класса. Во-первых, вы можете захотеть поставить точку останова при вызове определенного ctor или dtor. Кроме того, их определение не может привести к разрыву кода, поскольку компилятор будет генерировать встроенные вызовы членам ctor и dtor (у Скотта Мейерса есть раздел об этом).

Также вы иногда хотите запретить копии и назначения копирования по умолчанию. Например, у меня есть приложение, которое хранит и обрабатывает очень большие блоки данных. У нас обычно есть эквивалент вектора STL, содержащего миллионы 3D-точек, и это было бы катастрофой, если бы мы разрешили копирование этих контейнеров. Таким образом, операторы ctor и присваивания объявляются частными и не определены. Таким образом, если кто-нибудь пишет

class myClass {
  void doSomething(const bigDataContainer data); // not should be passed by reference
}

тогда они получат ошибку компилятора. Наш опыт заключается в том, что явный метод get() или clone() гораздо менее подвержен ошибкам.

Итак, у всех есть много причин, чтобы избежать автогенерируемых функций компилятора.

Ответ 5

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

Имеет ли мой класс какие-либо ресурсы?

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

Возможно, кто-то наследует мой класс?

Базовые классы нуждаются в деструкторе. Herb Sutter рекомендует сделать их как public, так и virtual (наиболее распространенный случай) или protected и не виртуальный, в зависимости от того, что вы хотите сделать с ними. Деструктор, созданный компилятором, является открытым и не виртуальным, поэтому вам придется писать свои собственные, даже если в нем нет никакого кода. (Примечание: это не означает, что вам нужно написать конструктор копирования или оператор присваивания.)

Должен ли я запретить пользователю копировать объекты моего класса?

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

Нижняя строка:

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

Ответ 6

для этого контейнера понадобится элемент "copy constructible", и если вы не предоставите конструктор копирования, он вызовет конструктор копии по умолчанию вашего класса, выведя его из ваших членов класса (мелкая копия).

простое объяснение о конструкторе копии по умолчанию находится здесь: http://www.fredosaurus.com/notes-cpp/oop-condestructors/copyconstructors.html

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

Ответ 7

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

Ответ 8

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

В частности, любой класс, содержащий указатели или ссылки, должен содержать их:

class foo {
private:
    int a,b;
    bar *c;
}

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

Ответ 9

Не для строк или векторов, поскольку тривиальные конструкторы/деструкторы и т.д. сделают все возможное.

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