C возвращает по ссылке, каковы последствия?

#c #reference #pass-by-reference #return-by-reference

#c #ссылка #передача по ссылке #возврат по ссылке

Вопрос:

Возьмем следующий код, где функция возвращает по ссылке:

 #include <cstdio>
using namespace std;

int amp; myFunction(int amp; input) {
    return input;
}

int main() {
    int x;
    int y = 10;
    x = myFunction(y);
    printf("x is %dn",x); // x is 10
    printf("y is %dn",y); // y is 10
    x = 20;
    printf("x is %dn",x); // x is 20
    printf("y is %dn",y); // y is 10
    return 0;
}
  

Кроме очевидной ошибки возврата ссылки на локальную переменную функции (что здесь не так), есть ли какие-либо вещи, на которые следует обратить внимание при такой настройке? Другими словами, есть ли в этом коде что-то «больше», чем функция, которая просто возвращает вещи по ссылке, чтобы избежать ненужных операций копирования?

Комментарии:

1. Извините, я этого не заметил. Этот случай в порядке.

2. Нет, больше ничего. На самом деле это часто делается с помощью операторов << и >>

3. » функция, которая просто возвращает вещи по ссылке, чтобы избежать ненужных операций копирования » Так ли это здесь, или вы подразумеваете, что это можно сделать в качестве оптимизации? Потому что обычно это делается для семантики, а не для преждевременной оптимизации.

4. Это нормально и делается в других местах. как @UKMonkey говорит, что сделано с операторами потока. например, здесь: en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt

5. этот код похож на стандартный оператор << для std::ostream . так что это обычный способ кодирования

Ответ №1:

Кроме очевидной ошибки возврата ссылки на локальную переменную функции (что здесь не так), есть ли какие-либо вещи, на которые следует обратить внимание при такой настройке?

Нет, не совсем, это совершенно справедливо, но и не имеет никакого преимущества. (в текущем состоянии myFunction )

чтобы избежать ненужных операций копирования?

Здесь все еще создается копия:

 int x;
int y = 10;
x = myFunction(y); // value of y is copied to x.
  

Это менее читабельно и ничего не ускоряет, когда дело доходит до обычной инициализации:

 int x;
int y = 10;
x = y;
  

В этой ситуации нет причин делать это, просто придерживайтесь обычной инициализации.

Конечно, если myFunction добавляет какую-то модификацию к более сложному объекту, чем intamp; тогда, вы можете воспользоваться возвращением ссылки, как только сможете:

 chain.method().calls();
  

Комментарии:

1. Спасибо! Да, конечно, myFunction() бесполезна, как и в моем примере кода. Я просто привел минимальный пример, о котором мы можем поговорить.

Ответ №2:

Предоставленный вами код работает, потому что вы передаете переменную в свою функцию по ссылке и все равно возвращаете ее по ссылке. Это согласованно и работает, но странно. Почему вы возвращаете ту же переменную, которую вы передаете по ссылке? (Я только что вспомнил из комментариев, что это полезно для цепочки в std::ostream, например.)

С другой стороны, если вы передадите эту переменную по значению, у вас будет висячая ссылка, и она не будет работать. Так что это не сработает:

 int amp; myFunction(int input) {
    return input;
}
  

На мой взгляд, единственный возврат по ссылке, который я считаю подходящим, — это если вы возвращаете переменную из метода класса. Кроме того, я не думаю, что вам вообще следует возвращать по ссылке.

Вы можете перехватить переменную как постоянную ссылку и избежать ее копирования, если хотите, без зависания, если вы сделаете это:

 int myFunction(int input) {
    return input;
}

int main()
{
    const intamp; myInt = myFunction();
    //myInt is still valid here
}
  

Это особый случай, который.

Комментарии:

1. Я имею в виду, что первая часть выполняется в самом stl. и о передаче по значению. В вопросе указано, что OP знает об этом.

2. Спасибо, я спрашиваю об этом конкретном случае (т. Е. Мы не ошибочно возвращаем ссылку на локальную переменную). Есть ли что-нибудь «еще» в этом сценарии?

3. @space_voyager Я не понимаю, зачем тебе это делать. Очень неоднозначно и нечитаемо передавать по ссылке и возвращать одну и ту же переменную по ссылке…

4. @TheQuantumPhysicist это прекрасно читается; фактически это УЛУЧШАЕТ читаемость! Давайте посмотрим на cout << foo << bar << baz ; как вы думаете, << возвращается для использования таким образом? Это также делается в шаблоне builder. foo().SetActive().setBaz()

5. @UKMonkey Ну, ты прав. Это полезно и для цепочки. Я забыл об этом.