Реализация конструктора копирования в терминах operator = - PullRequest
19 голосов
/ 06 сентября 2010

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

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

Ответы [ 8 ]

27 голосов
/ 06 сентября 2010

Если все члены 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;
}

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

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

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

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

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

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

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

11 голосов
/ 06 сентября 2010

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

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

5 голосов
/ 06 сентября 2010

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

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

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

1 голос
/ 06 сентября 2010

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

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

struct C {
   ExpensiveType member;

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



 };
0 голосов
/ 05 октября 2011

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

Однако вы должны предпочесть копирование и обмен, потому что:

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

@ Александр - я не уверен в передаче значения в операторе присваивания.Какое преимущество вы получите, вызвав там конструктор копирования?Это собирается закрепить оператор присваивания?

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

0 голосов
/ 06 сентября 2010

да.

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

0 голосов
/ 06 сентября 2010

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

...