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

Реализация конструктора копирования в терминах оператора =

Если параметр operator= правильно определен, можно ли использовать следующее как конструктор копирования?

MyClass::MyClass(MyClass const &_copy)
{
    *this = _copy;
}
4b9b3361

Ответ 1

Если все члены MyClass имеют конструктор по умолчанию, да.

Обратите внимание, что обычно это наоборот:

class MyClass
{
public:
    MyClass(MyClass const&);     // Implemented
    void swap(MyClass&) throw(); // Implemented
    MyClass& operator=(MyClass rhs) { rhs.swap(*this); return *this; }
};

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

ИЗМЕНИТЬ, в соответствии с запросом, о материалах по умолчанию: operator= может быть записано как

MyClass& MyClass::operator=(MyClass const& rhs)
{
    MyClass tmp(rhs);
    tmp.swap(*this);
    return *this;
}

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

Таким образом, operator= (первая версия, вызов по значению) читает:

  • Сделайте копию rhs (через автоматически созданный конструктор копирования)
  • Поменяйте содержимое *this
  • Возврат *this и rhs (который содержит старое значение) будет уничтожен при выходе метода.

Теперь у нас есть дополнительный бонус с этим по умолчанию. Если объект, передаваемый operator= (или любая функция, которая получает свои аргументы по значению), является временным объектом, компилятор может (и обычно делает) вообще не копировать. Это называется копией.

Следовательно, если rhs является временным, копия не производится. Осталось:

  • Swap this и rhs содержимое
  • Уничтожить rhs

Таким образом, передача по значению в этом случае более эффективна, чем передача по ссылке.

Ответ 2

Более целесообразно реализовать operator = с точки зрения конструктора исключаемых копий. См. Пример 4. в этом от Herb Sutter для объяснения техники и почему это хорошая идея.

http://www.gotw.ca/gotw/059.htm

Ответ 3

Эта реализация подразумевает, что конструкторы по умолчанию для всех членов данных (и базовых классов) доступны и доступны из MyClass, потому что они будут вызваны первыми, прежде чем выполнять назначение. Даже в этом случае наличие дополнительного вызова для конструкторов может быть дорогостоящим (в зависимости от содержания класса).

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

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

Ответ 4

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

С "дорогим" членом лучше скопировать-конструкцию с помощью списка инициализаторов.

struct C {
   ExpensiveType member;

   C( const C& other ): member(other.member) {}
};



 };

Ответ 5

Я бы сказал, что это не нормально, если MyClass выделяет память или изменяет ее.

Ответ 6

да.

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

Ответ 7

@Alexandre - я не уверен в передаче по значению в операторе присваивания. В чем преимущество, которое вы получите, позвонив в конструктор копирования? Будет ли это закрепление оператора присваивания?

P.S. Я не знаю, как писать комментарии. Или может быть, мне не разрешено писать комментарии.

Ответ 8

Это технически нормально, если у вас есть оператор рабочего назначения (оператор копирования).

Однако вы должны предпочесть copy-and-swap, потому что:

  • Безопасность исключений проще с помощью копирования-замены
  • Наиболее логичное разделение проблем:
    • Copy-ctor - это распределение ресурсов, которые ему нужны (для копирования других материалов).
    • Функция обмена (в основном) только об обмене внутренних "дескрипторов" и не требует выделения ресурсов (де)
    • Деструктор - это освобождение ресурсов
    • Copy-and-swap естественно объединяет эти три функции в операторе присваивания/копирования