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

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

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


person user997112    schedule 26.10.2013    source источник
comment
См. Правило трех. Полезно знать, что если вы приобретаете какой-либо ресурс и вам нужно удалить или очистить его, вам, вероятно, потребуется определить три операции (четыре в C++11 для работы с семантикой перемещения): stackoverflow.com/questions/4172722/what-is-the-rule- из трех   -  person Escualo    schedule 26.10.2013


Ответы (4)


Указатели, несомненно, самый очевидный случай, но не единственный.

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

person Jerry Coffin    schedule 26.10.2013

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

Только если вам нужна копия данных, вы должны исправить конструктор копирования.

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

person Bozemoto    schedule 26.10.2013

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

В случае с потоком этому конструктору копирования может потребоваться

а) дублировать файл,

б) создать новый пустой файл, в который можно записать,

в) или сохранить адрес потока, чтобы в него могли писать оба объекта.

Последний вариант является наиболее сложным и, вероятно, потребует использования файла shared_ptr.

person HarrySarson    schedule 26.10.2013

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

Что не так очевидно, так это то, что некоторым классам, не поддерживающим ресурсы напрямую, может потребоваться присваивание копирования: если вы хотите, чтобы присваивание копирования было строго безопасным для исключений, вам часто нужно реализовать присваивание копирования. Например, предположим, что ваш класс хранит два вектора. Сгенерированное назначение копии выполняет назначение для отдельных элементов. Обычно почленное назначение подходит. Однако, если присваивание второму вектору выдает исключение, восстановить исходное состояние невозможно! Лучшее задание копирования будет выглядеть так:

T& T::operator= (T other) {
    other. swap(*this);
    return *this;
}

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

person Dietmar Kühl    schedule 26.10.2013