Подтвердить что ты не робот

С++ Возвращаемое значение, ссылка, ссылка на константу

Можете ли вы объяснить мне разницу между возвращаемым значением, ссылкой на значение и константой ссылки на значение?

Значение:

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 Vector2D& operator += (const Vector2D& vector)
{
    this->x += vector.x;
    this->y += vector.y;
    return *this;
}

В чем преимущество этого? Я понимаю, что смысл ссылки на const ссылается на функцию, так как вы хотите не изменять это значение, на которое ссылается ссылка внутри функции. Но я смущен значением возвращаемой ссылки const. Почему возвращение ссылки лучше, чем возврат значения, и почему возвращение ссылки const лучше, чем возврат ссылки not-const?

4b9b3361

Ответ 1

Нет никакой разницы, если вы не напишете что-то странное, как

(v1 += v2) = v3;

В первом случае назначение будет временным, а общий эффект будет v1 += v2.

Во втором случае назначение будет v1, поэтому общий эффект будет v1 = v3.

В третьем случае присваивание не будет разрешено. Вероятно, это лучший вариант, поскольку такая странность почти наверняка является ошибкой.

Почему возвращение ссылки лучше возврата значения?

Это потенциально более эффективно: вам не нужно делать копию объекта.

и почему возвращение ссылки const лучше, чем возврат ссылки not-const?

Вы предотвращаете странность, как в приведенном выше примере, но при этом допускаете менее странную цепочку, такую ​​как

v1 = (v2 += v3);

Но, как отмечено в комментариях, это означает, что ваш тип не поддерживает те же формы (ab), которые используются как встроенные типы, которые некоторые считают желательными.

Ответ 2

Это точно так же, как передать аргумент функции.

Вы хотите вернуть ссылку const, когда вы возвращаете свойство объекта, которое вы не хотите изменять вне его. Например: когда ваш объект имеет имя, вы можете сделать следующий метод const std::string& get_name(){ return name; };. Это самый оптимальный способ. Вы разрешаете доступ только для чтения к внутреннему свойству с отсутствием копирования по возврату.

Когда вы перегружаете операторы, вы должны вернуть объект, который изменен, в противном случае некоторый определенный синтаксис, который обычно ожидается, приведет к ошибкам. Это очень важно, когда вы пробуете странную цепочку.

Например, опция 3 не будет работать с чем-то вроде (v1 += v2).non_const_method(), While, следующее:

v1+=v2;
v1.non_const_method();

Ответ 3

Значение:

Возврат по значению означает, что вы возвращаете копию объекта. Это ставит требования к классу (его нужно копировать или перемещать). Это означает, что для объекта некоторых классов, возвращающихся по значению, может быть дорого (в случае, когда RVO или NRVO не работают или отключены). Это также означает, что новый объект является независимым (с учетом его дизайна) от других объектов и является его собственным значением. Это то, что вы, вероятно, должны вернуться от многих двоичных операторов, таких как +, -, * и т.д.

Неконстантная ссылка:

Вы действительно возвращаете псевдоним для другого объекта. Псевдоним, не являющийся const, позволяет вам изменять объект с псевдонимом. Это то, что вы должны возвращать из некоторых унарных форвардов, таких как prefix ++ и -, и * (разыменование), поскольку вы обычно хотите иметь возможность изменять возвращенный объект.

Это возвращается оператором → , а оператор < < перегружен для потоков. Это позволяет цепочки операторов:

cout << 5 << "is greater then" << 1 << endl;
cin >> myInt >> myFloat;

Вы также можете вернуть ссылку на * это, когда хотите разрешить цепочку регулярных методов, таких как:

object.run().printLastRunStatistics();

Ссылка на константу:

Как и выше, но вы НЕ МОЖЕТЕ модифицировать объект с псевдонимом. Может использоваться вместо возврата по значению, когда возвращаемый объект дорого копируется и когда вы можете обеспечить его существование после возврата из функции.

Это то, что оператор = обычно возвращает, чтобы разрешить несколько назначений таким образом, чтобы их поддерживали стандартные типы:

a = b = c;

Константа-ссылка, используемая в operator = предотвращает такой тип использования (не поддерживается стандартным типом, насколько я помню):

++(a = b);

который был бы разрешен, если бы использовалась нормальная ссылка.

Ответ 4

Разница между return-by-value и return-by-reference вступает в силу во время выполнения:

Когда вы возвращаете объект по значению, вызывается экземпляр-экземпляр и создается временный экземпляр в стеке.

Когда вы возвращаете ссылку на объект, все вышеперечисленное не имеет места, что приводит к повышению производительности.


Разница между return-by-reference и return-by-constant-reference не имеет эффекта времени исполнения и просто защищает вас от написания ошибочных код.

Например, с помощью Vector2D& operator += (const Vector2D& vector) вы можете сделать:

(x+=y)++ или (x+=y).func(), где func является неконстантной функцией в классе Vector2D.

Но с const Vector2D& operator += (const Vector2D& vector) компилятор генерирует ошибку для любой подобной попытки.

Ответ 5

Как указано, но luk32, это просто гарантировать, что никакие изменения не будут разрешены объектам, возвращаемым этой функцией. Это может помочь вам найти логические ошибки во время компиляции. Предположим, что вы не хотите менять объект, а ваш код меняет объект, его можно отслеживать. Можно подумать о хорошей практике кодирования.