Оператор 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,

Другие вопросы по тегам