C++ Возвращаемое значение, ссылка, константная ссылка
Можете ли вы объяснить мне разницу между возвращаемым значением, ссылкой на значение и константной ссылкой на значение?
Значение:
Vector2D operator += (const Vector2D& vector)
{
this->x += vector.x;
this->y += vector.y;
return *this;
}
Неконстантная ссылка:
Vector2D& operator += (const Vector2D& vector)
{
this->x += vector.x;
this->y += vector.y;
return *this;
}
Const ссылка:
const Vector2D& operator += (const Vector2D& vector)
{
this->x += vector.x;
this->y += vector.y;
return *this;
}
В чем выгода этого? Я понимаю смысл передачи константной ссылки в функцию, поскольку вы хотите не изменять это значение, на которое ссылается ссылка внутри функции. Но меня смущает смысл возврата константной ссылки. Почему возврат ссылки лучше, чем возврат значения, и почему возврат константной ссылки лучше, чем возврат неконстантной ссылки?
5 ответов
Нет разницы, если вы не напишите что-то странное, как
(v1 += v2) = v3;
В первом случае назначение будет временным, а общий эффект будет v1 += v2
,
Во втором случае назначение будет v1
, так что общий эффект будет v1 = v3
,
В третьем случае назначение не будет разрешено. Это, вероятно, лучший вариант, поскольку такая странность почти наверняка является ошибкой.
Почему возврат ссылки лучше, чем возврат значения?
Это потенциально более эффективно: вам не нужно делать копию объекта.
и почему возврат константной ссылки лучше, чем возврат неконстантной ссылки?
Вы предотвращаете странности, как в приведенном выше примере, и в то же время разрешаете менее странные цепочки, такие как
v1 = (v2 += v3);
Но, как отмечено в комментариях, это означает, что ваш тип не поддерживает те же формы использования (ab), что и встроенные типы, что некоторые люди считают желательным.
Значение:
Возврат по значению означает, что вы возвращаете копию объекта. Это предъявляет требования к классу (он должен быть копируемым или перемещаемым). Это означает, что для объекта некоторых классов возврат по значению может быть дорогостоящим (в случае, когда RVO или NRVO не работает или выключен). Это также означает, что новый объект является независимым (в зависимости от его дизайна) от других объектов и является собственной ценностью. Это то, что вы, вероятно, должны возвращать из многих бинарных операторов, таких как +, -, * и так далее.
Неконстантная ссылка:
Вы действительно возвращаете псевдоним для другого объекта. Псевдоним, не являющийся const, позволяет вам изменять объект с псевдонимом. Это то, что вы должны возвращать из некоторых унарных операторов, таких как префикс ++ и - и * (разыменование), поскольку вы обычно хотите иметь возможность изменять возвращаемый объект.
Это возвращается оператором >> и оператором<<, перегруженным для потоков. Это позволяет создавать цепочки операторов:
cout << 5 << "is greater then" << 1 << endl;
cin >> myInt >> myFloat;
Вы также можете вернуть ссылку на *this, если хотите разрешить цепочку обычных методов, таких как эта:
object.run().printLastRunStatistics();
Const ссылка:
Как и выше, но вы НЕ МОЖЕТЕ изменить псевдоним. Может использоваться вместо возврата по значению, когда возвращаемый объект дорогостоящ для копирования и когда вы можете обеспечить его существование после возврата из функции.
Вот что обычно возвращает operator=, чтобы разрешить множественные присваивания таким образом, как их поддерживают стандартные типы:
a = b = c;
Const-ссылка, используемая в operator=, предотвращает использование такого типа (насколько я помню, не поддерживается стандартным типом):
++(a = b);
что было бы разрешено, если бы использовалась нормальная ссылка.
Разница между возвратом по значению и возвратом по ссылке вступает в силу во время выполнения:
Когда вы возвращаете объект по значению, вызывается конструктор копирования, и в стеке создается временный экземпляр.
Когда вы возвращаете объект по ссылке, все вышеперечисленное не происходит, что приводит к повышению производительности.
Разница между возвратом по ссылке и возвратом по постоянной ссылке не имеет никакого эффекта во время выполнения и просто защищает вас от написания ошибочного кода.
Например, с Vector2D& operator += (const Vector2D& vector)
, ты можешь сделать:
(x+=y)++
или же (x+=y).func()
где func
неконстантная функция в классе Vector2D
,
Но с const Vector2D& operator += (const Vector2D& vector)
, компилятор выдаст ошибку для любой подобной попытки.
Это точно так же, как передача аргумента функции.
Вы хотите вернуть const
ссылка, когда вы возвращаете свойство объекта, которое вы не хотите изменять вне его. Например: когда у вашего объекта есть имя, вы можете сделать следующий метод const std::string& get_name(){ return name; };
, Какой самый оптимальный способ. Вы разрешаете доступ "только для чтения" к внутреннему свойству без копирования при возврате.
Когда вы перегружаете операторы, вы должны вернуть объект, который является изменяемым, в противном случае некоторый определенный синтаксис, который обычно должен работать, приведет к ошибкам. Это очень важно, когда вы пытаетесь использовать странные цепочки.
Например, вариант 3 не будет работать с чем-то вроде (v1 += v2).non_const_method()
, В то время как следующее будет:
v1+=v2;
v1.non_const_method();
Как указывалось, но luk32 просто гарантирует, что никакие изменения не допускаются к объектам, возвращаемым этой функцией. В основном это может помочь вам найти логические ошибки во время компиляции. Предположим, что вы уверены, что не измените объект, и ваш код изменяет объект, его можно отслеживать. Можно подумать о хорошей практике кодирования.