Кто-нибудь обнаружил необходимость объявить возвращаемый параметр оператора присваивания копии const?
Оператор присвоения копии имеет обычную подпись:
my_class & operator = (my_class const & rhs);
Имеет ли следующая подпись какое-либо практическое применение?
my_class const & operator = (my_class const & rhs);
Вы можете определить только один или другой, но не оба.
7 ответов
Основная причина сделать возвращаемый тип копирования-присвоения неконстантной ссылкой заключается в том, что в стандарте это требование "Назначаемое".
Если вы делаете возврат типа const
в этом случае ваш класс не будет соответствовать требованиям для использования в любом из стандартных контейнеров библиотеки.
Не делай этого. Это мешает клиенту написать что-то вроде:
(a = b).non_const_method();
вместо более длинной формы:
a = b;
a.non_const_method();
Хотя вам может не понравиться этот сокращенный стиль, пользователь библиотеки сам решает, как он хочет написать код.
Ответ, который отражает ответ оператора перегрузки в C++:
Возвращение const&
все еще разрешит цепочку назначений:
a = b = c;
Но запретит некоторые из более необычных применений:
(a = b) = c;
Обратите внимание, что это заставляет оператор присваивания иметь семантику, аналогичную той, что есть в Си, где значение, возвращаемое =
оператор не является lvalue. В C++ стандарт изменил это так, чтобы =
Оператор возвращает тип левого операнда, поэтому результатом является lvalue. Но, как отметил Стив Джессоп в комментарии к другому ответу, компилятор примет его.
(a = b) = c;
даже для встроенных функций результатом является неопределенное поведение встроенных a
изменяется дважды без промежуточной точки последовательности. Этой проблемы избегают для не встроенных operator=()
поскольку operator=()
Вызов функции служит точкой последовательности.
Я не вижу проблем с возвратом const&
если вы не хотите специально разрешить семантику lvalue (и спроектировать класс так, чтобы он действовал разумно с этой семантикой). Если вы пользователи хотите сделать что-то необычное с результатом operator=()
Я бы предпочел, чтобы класс запретил это, а не надеялся, что он получит это случайно, а не дизайн.
Также. обратите внимание, что в то время как вы сказали:
Вы можете определить только один или другой, но не оба.
это потому, что сигнатура функции в C++ не учитывает тип возвращаемого значения. Вы могли бы, однако, иметь несколько operator=()
Операторы присваивания, которые принимают разные параметры и возвращают разные типы, соответствующие типам параметров:
my_class& operator=( my_class& rhs);
my_class const& operator=(my_class const& rhs);
Я не совсем уверен, что это купит вас, хотя. Присваиваемый объект (предположительно возвращаемая ссылка) неконстантен в обоих случаях, поэтому нет логической причины возвращать const&
только потому, что правая сторона =
является const
, Но, может быть, я что-то упустил...
Эффективный 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
}
...
};
Почему все одержимы (a = b) = c
? Это когда-нибудь было написано случайно?
Вероятно, есть некоторая непредвиденная полезность результата изменения назначения. Вы не просто делаете произвольные правила против вымышленных примеров, которые выглядят смешно. Семантически нет причин, что это должно быть const
так что не объявляй const
для лексических побочных эффектов.
Вот пример несколько разумного кода, который ломается для const &
назначение:
my_class &ref = a = b;
Как и при любом другом использовании const, const является значением по умолчанию, если вы действительно не хотите, чтобы пользователь изменился.
Да должно быть const
, В противном случае клиенты могут сделать это:
class MyClass
{
public:
MyClass & operator = (MyClass const & rhs);
}
void Foo() {
MyClass a, b, c;
(a = b) = c; //Yikes!
}