По-прежнему ли я получаю конструктор копирования по умолчанию и оператор =, если я определяю их с неконстантными аргументами?

В С++, если я определяю конструктор копирования и оператор =, которые принимают неконстантную ссылку на класс, должен ли компилятор по-прежнему предоставлять версии по умолчанию для константной ссылки?

struct Test {
  Test(Test &rhs);
  Test &operator=(Test &rhs);

private:
  // Do I still need to declare these to avoid automatic definitions?
  Test(const Test &rhs);
  Test &operator=(const Test &rhs);
};

person WilliamKF    schedule 13.08.2012    source источник


Ответы (2)


Нет, если вы определите конструктор копирования и оператор присваивания, компилятор не будет неявно объявлять или определять свои собственные. Обратите внимание, что определение копирующего-конструктора позволяет аргументу принимать константную или неконстантную ссылку, поэтому ваш конструктор действительно является копирующим-конструктором. Аналогично для operator=

[Опуская большую часть деталей, в частности, при каких обстоятельствах неявно объявленные специальные функции-члены также будут неявно определены]

12.8 [class.copy]/2 Нешаблонный конструктор для класса X является конструктором копирования, если его первый параметр имеет тип X&, const X&, volatile X& или const volatile X&, и либо нет других параметров, либо все остальные параметры имеют аргументы по умолчанию (8.3.6).

12.8 [class.copy]/7 Если определение класса явно не объявляет конструктор копирования, он объявляется неявно.

12.8 [class.copy]/17 Объявленный пользователем оператор присваивания копии X::operator= — это нестатическая нешаблонная функция-член класса X с ровно одним параметром типа X, X&, const X&, volatile X& или const летучий X&.

12.8 [class.copy]/18 Если определение класса явно не объявляет оператор присваивания копирования, он объявляется неявно.

person David Rodríguez - dribeas    schedule 13.08.2012

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

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

Если вы пытаетесь реализовать семантику перемещения и не можете использовать С++ 11, я бы предложил создать специальный метод перемещения и вообще не разрешать построение "перемещения". Если вы можете использовать С++ 11, используйте встроенные ссылки rvalue.

person Mark B    schedule 13.08.2012