Когда я читал это объяснение lvalues и rvalues, мне запомнились следующие строки кода:
int& foo();
foo() = 42; // OK, foo() is an lvalue
Я пробовал это в g ++, но компилятор говорит «неопределенная ссылка на foo ()». Если я добавлю
int foo()
{
return 2;
}
int main()
{
int& foo();
foo() = 42;
}
Он компилируется нормально, но при его запуске возникает ошибка сегментации . Просто линия
int& foo();
сам по себе компилируется и запускается без каких-либо проблем.
Что означает этот код? Как можно присвоить значение вызову функции и почему это не rvalue?
c++
function
return-by-reference
Sossisos
источник
источник
Ответы:
Объяснение предполагает, что существует некая разумная реализация, для
foo
которой возвращается ссылка lvalue на действительныйint
.Такой реализацией может быть:
Теперь, поскольку
foo
возвращает ссылку lvalue, мы можем присвоить что-нибудь возвращаемому значению, например:Это обновит глобал
a
со значением42
, которое мы можем проверить, обратившись к переменной напрямую или вызвавfoo
снова:источник
Все остальные ответы объявляют статику внутри функции. Я думаю, это может вас запутать, поэтому взгляните на это:
Поскольку
highest()
возвращает ссылку, вы можете присвоить ей значение. При его запуске значениеb
будет изменено на 11. Если вы изменили инициализациюa
, например, на 8, тоa
оно будет изменено на 11. Это некоторый код, который действительно может служить определенной цели, в отличие от других примеров.источник
Объявляет функцию с именем foo, которая возвращает ссылку на
int
. Эти примеры не позволяют дать вам определение функции, которую вы могли бы скомпилировать. Если мы используемТеперь у нас есть функция, которая возвращает ссылку на
bar
. так как barstatic
он будет жить после вызова функции, поэтому возврат ссылки на него безопасен. Теперь, если мы сделаемЧто происходит, мы назначаем 42,
bar
поскольку мы назначаем ссылку, а ссылка является просто псевдонимом дляbar
. Если мы снова вызовем функцию, напримерОн напечатает 42, так как мы установили
bar
это выше.источник
int &foo();
объявляет функцию, вызываемуюfoo()
с возвращаемым типомint&
. Если вы вызовете эту функцию без указания тела, вы, вероятно, получите ошибку неопределенной ссылки.Во второй попытке вы предоставили функцию
int foo()
. Это имеет другой тип возвращаемого значения по сравнению с функцией, объявленнойint& foo();
. Итак, у вас есть два объявления одного и того же,foo
которые не совпадают, что нарушает правило одного определения, вызывая неопределенное поведение (диагностика не требуется).Если что-то работает, удалите объявление локальной функции. Как вы видели, они могут вести к бесшумному неопределенному поведению. Вместо этого используйте только объявления функций вне любой функции. Ваша программа могла бы выглядеть так:
источник
int& foo();
это функция, возвращающая ссылку наint
. Ваша предоставленная функция возвращаетсяint
без ссылки.Вы можете сделать
источник
int & foo();
означает, чтоfoo()
возвращает ссылку на переменную.Рассмотрим этот код:
Этот код печатает:
$ ./a.out k = 5
Потому что
foo()
возвращает ссылку на глобальную переменнуюk
.В пересмотренном коде вы приводите возвращаемое значение к ссылке, которая в таком случае недействительна.
источник
В этом контексте & означает ссылку, поэтому foo возвращает ссылку на int, а не на int.
Я не уверен, что вы еще работали с указателями, но идея аналогичная, вы фактически не возвращаете значение из функции - вместо этого вы передаете информацию, необходимую для поиска места в памяти, где это int есть.
Итак, чтобы подвести итог, вы не присваиваете значение вызову функции - вы используете функцию для получения ссылки, а затем присваиваете значение, на которое ссылается, новому значению. Легко представить, что все происходит сразу, но на самом деле компьютер делает все в точном порядке.
Если вам интересно - причина, по которой вы получаете segfault, заключается в том, что вы возвращаете числовой литерал '2' - так что это точная ошибка, которую вы получили бы, если бы вы определяли const int, а затем пытались изменить его стоимость.
Если вы еще не узнали об указателях и динамической памяти, я бы порекомендовал это в первую очередь, так как есть несколько концепций, которые, на мой взгляд, трудно понять, если вы не изучите их все сразу.
источник
Пример кода на связанной странице - это просто объявление фиктивной функции. Он не компилируется, но если бы у вас была определена какая-то функция, она работала бы в целом. Пример означал: «Если у вас есть функция с этой подписью, вы можете использовать ее так».
В вашем примере
foo
явно возвращается lvalue на основе подписи, но вы возвращаете rvalue, преобразованное в lvalue. Это явно обречено на провал. Вы могли сделать:и преуспеет, изменив значение x, когда скажет:
источник
У вас есть функция foo (), которая возвращает ссылку на целое число.
Итак, предположим, что изначально foo вернул 5, а позже в вашей основной функции, вы говорите
foo() = 10;
, затем распечатает foo, он напечатает 10 вместо 5.Надеюсь это имеет смысл :)
Я тоже новичок в программировании. Интересно видеть такие вопросы, которые заставляют задуматься! :)
источник