Оператор C++ = вернуть ссылку на *this
Посмотрите на следующий код:
#include <iostream>
using namespace std;
class Widet{
public:
Widet(int val = 0):value(val)
{
}
Widet& operator=(Widet &rhs)
{
value = rhs.value;
return *this;
}
int getValue()
{
return value;
}
private:
int value;
};
int main()
{
Widet obj1(1);
Widet obj2(2);
Widet obj3(0);
(obj3 = obj2) = obj1;
cout << "obj3 = " << obj3.getValue() << endl;
}
Код выполняется успешно, и вывод (с использованием VS2008):
Когда я позволю оператору = вернуть значение вместо ссылки:
Widet operator=(Widet &rhs)
{
value = rhs.value;
return *this;
}
Он также работает успешно, и вывод:
Мой вопрос: почему второй код работает хорошо? Разве мы не должны получить ошибку?
Почему это хорошая привычка возвращать ссылку на * это вместо * этого?
7 ответов
Почему второй код работает хорошо? Разве мы не должны получить ошибку?
Потому что это совершенно правильный код. Он возвращает временную копию объекта, и вы можете вызывать функции-члены (включая operator=()
) на временных объектах, поэтому ошибок нет.
Вы получите ошибку, если объект не будет скопирован.
Почему это хорошая привычка возвращать ссылку на * это вместо * этого?
Поскольку не все объекты являются копируемыми, а некоторые объекты являются дорогостоящими для копирования. Вы можете взять ссылку на любой объект, и ссылки всегда дешевы для передачи.
Обычно вы возвращаете ссылку, чтобы можно было использовать =
Оператор как L-значение.
Когда вы не вернете ссылку, (obj3 = obj2)
дает временную копию obj3
, Копия получает значение от obj1
и удаляется, в то время как obje3
никогда не зависит от второго назначения.
Почему второй код работает хорошо? Разве мы не должны получить ошибку?
Он выполняется потому, что неконстантные функции-члены также могут вызываться для (неконстантных) значений класса. Вторая версия operator=
возвращает неконстантный класс rvalue, поэтому, по сути, вы присваиваете временное значение, оставляя предыдущее значение в obj3
переменная.
Следовательно, ошибки нет.
Во втором примере вы создаете временную копию (копию Obj3, возвращенную оператором =) и назначаете ей Obj1. Тогда это немедленно разрушается. Obj3 остается результатом первого назначения - Obj3 = Obj2
,
Возврат ссылки из оператора =() включает выражения вроде:
a=b=c;
Возврат значения может быть чрезмерным, когда вам это не нужно. Это может вызвать дополнительные вызовы копирования-конструктора / деструктора. В противном случае возвращаемое значение является абсолютно допустимым в C++. Люди, пожалуйста, исправьте меня, если я ошибаюсь, но я думаю, что возвращение по значению не является большой проблемой в C++11 из-за семантики перемещения.
(obj3 = obj2)
можно рассматривать как obj3operator=(obj2)
// гипотетически.
Поскольку вы передали obj2 в качестве параметра, перегрузка вашего оператора скопирует obj2.value в obj3.value.
(obj3 = obj2) = obj1;
После возвращения из operator=
, obj3(* this, временная копия) будет возвращено.
Таким образом, эквивалентный код становится obj3=obj1
который снова вызовет operator=
из obj3
и сбросит значение obj3.value
в obj1.value
т.е. 1
,