Кто-нибудь обнаружил необходимость объявить возвращаемый параметр оператора присваивания копии const? - PullRequest
9 голосов
/ 16 апреля 2010

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

    my_class & operator = (my_class const & rhs);

Имеет ли практическая польза следующая подпись?

    my_class const & operator = (my_class const & rhs);

Вы можете определить только одно или другое, но не оба.

Ответы [ 7 ]

18 голосов
/ 16 апреля 2010

Принципиальная причина для того, чтобы сделать возвращаемый тип назначения копирования неконстантной ссылкой, состоит в том, что это требование для «Назначаемого» в стандарте.

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

6 голосов
/ 16 апреля 2010

Не делай этого. Это мешает клиенту написать что-то вроде:

(a = b).non_const_method();

вместо более длинной формы:

a = b;
a.non_const_method();

Несмотря на то, что вам может не понравиться стиль записи, пользователь библиотеки сам решает, как он хочет написать код.

3 голосов
/ 16 апреля 2010

Ответ, который отражает один из Перегрузка оператора присваивания в C ++ :

Возвращение const& все еще разрешит цепочку присвоения:

a = b = c;

Но запретитнекоторые из более необычных применений:

(a = b) = c;

Обратите внимание, что это делает оператор присваивания семантикой, аналогичной той, которая используется в C, где значение, возвращаемое оператором =, не является lvalue.В C ++ стандарт изменил его, поэтому оператор = возвращает тип левого операнда, поэтому результатом является lvalue.Но , как отметил Стив Джессоп в комментарии к другому ответу , в то время как это делает так, что компилятор будет принимать

(a = b) = c;

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

Я не вижу проблем с возвратом const&, если вы не хотите специально разрешить семантику lvalue(и разработайте класс так, чтобы он действовал разумно с этой семантикой).Если ваши пользователи хотят сделать что-то необычное с результатом operator=(), я бы предпочел, чтобы класс запретил это, а не надеялся, что он получит это случайно, а не дизайн.

Также.обратите внимание, что хотя вы сказали:

Вы можете определить только одно или другое, но не оба.

, потому что сигнатура функции в C ++ не учитываеттип возвращаемого значения.Однако вы можете иметь несколько operator=() операторов присваивания, которые принимают разные параметры и возвращают разные типы, соответствующие типам параметров:

my_class& operator=( my_class& rhs);
my_class const& operator=(my_class const& rhs);

Хотя я не совсем уверен, что это купит вас.Присваиваемый объект (предположительно возвращаемая ссылка) неконстантен в обоих случаях, поэтому нет логической причины возвращать const& только потому, что правая часть = равна const,Но, может быть, я что-то упустил ...

2 голосов
/ 16 апреля 2010

Почему все одержимы более (a = b) = c? Это когда-нибудь было написано случайно?

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

Вот пример несколько разумного кода, который ломается для присваивания const &:

my_class &ref = a = b;
2 голосов
/ 16 апреля 2010

В эффективном C ++ объясняется, что это нарушит совместимость со встроенными типами C ++.

Вы можете сделать это с помощью простого int s:

(x = y) = z;

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

Этот пример есть во 2-м издании, но больше не в 3-м. Тем не менее, эта цитата из 3-го ред., Пункт 10 говорит то же самое еще:

[...] присваивание возвращает ссылку на свой левый аргумент, и это соглашение, которому вы должны следовать при реализации операторов присваивания для ваших классов:

class Widget {
public:
  ...
  Widget& operator=(const Widget& rhs)   // return type is a reference to
  {                                      // the current class
  ...
  return *this;                        // return the left-hand object
  }
  ...
};
0 голосов
/ 16 апреля 2010

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

0 голосов
/ 16 апреля 2010

Да, это должно быть const. В противном случае клиенты могут сделать это:

class MyClass
{
public:
      MyClass & operator = (MyClass const & rhs);
}

void Foo() {
    MyClass a, b, c;
    (a = b) = c; //Yikes!
}
...