Что означает "int& foo ()" в C++?
во время чтения данное объяснение на 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?
9 ответов:
объяснение предполагает, что существует некоторая разумная реализация для
fooкоторый возвращает ссылку lvalue на действительныйint.такая реализация может быть такой:
int a = 2; //global variable, lives until program termination int& foo() { return a; }вот так
fooвозвращает ссылку lvalue, мы можем назначить что-то возвращаемое значение, например:foo() = 42;это обновит глобальный
aсо значением42, который мы можем проверить, обратившись к переменной напрямую или вызвавfooи снова:int main() { foo() = 42; std::cout << a; //prints 42 std::cout << foo(); //also prints 42 }
все остальные ответы объявить static внутри функции. Я думаю, что это может смутить вас, поэтому взгляните на это:
int& highest(int & i, int & j) { if (i > j) { return i; } return j; } int main() { int a{ 3}; int b{ 4 }; highest(a, b) = 11; return 0; }, потому что
highest()возвращает ссылку, вы можете присвоить ей значение. Когда это работает,bбудет изменено на 11. Если вы изменили инициализацию так, чтоaбыло, скажем, 8, тогдаaбудет изменено на 11. Это некоторый код, который может действительно служить цели, в отличие от других примеров.
int& foo();объявляет функцию с именем foo, которая возвращает ссылку на элемент
int. То, что примеры не могут сделать, это дать вам определение этой функции, которую вы могли бы скомпилировать. Если мы используемint & foo() { static int bar = 0; return bar; }теперь у нас есть функция, которая возвращает ссылку на
bar. так как бар-этоstaticон будет жить после вызова функции, поэтому возврат ссылки на него безопасен. Теперь, если мы сделаемfoo() = 42;что происходит, мы назначаем 42
barтак как мы назначьте ссылку, и ссылка - это просто псевдоним дляbar. Если мы снова вызовем функцию какstd::cout << foo();он будет печатать 42, так как мы установили
barДля что выше.
int &foo();объявляет функцию с именемfoo()С возвращением типаint&. Если вы вызываете эту функцию без предоставления тела, то вы, вероятно, получите неопределенную ошибку ссылки.во второй попытке вы предоставили функцию
int foo(). Это имеет другой тип возврата к функции, объявленнойint& foo();. Итак, у вас есть два объявления одного и того жеfooэто не соответствует, что нарушает одно правило определения, вызывающее неопределенное поведение (без диагностики требовать.)для чего-то, что работает, выньте объявление локальной функции. Они могут привести к молчаливому неопределенному поведению, как вы видели. Вместо этого используйте только объявления функций вне любой функции. Ваша программа может выглядеть так:
int &foo() { static int i = 2; return i; } int main() { ++foo(); std::cout << foo() << '\n'; }
int& foo();- это функция, возвращающая ссылку наint. Предоставленная функция возвращаетintбез ссылок.вы можете
int& foo() { static int i = 42; return i; } int main() { int& foo(); foo() = 42; }
int & foo();означает, чтоfoo()возвращает ссылку на переменную.рассмотрим этот код:
#include <iostream> int k = 0; int &foo() { return k; } int main(int argc,char **argv) { k = 4; foo() = 5; std::cout << "k=" << k << "\n"; return 0; }печатается код:
$ ./а.из k=5
, потому что
foo()возвращает ссылку на глобальную переменнуюk.в вашем пересмотренном коде вы приводите возвращенное значение к ссылке, которая затем недействительна.
в этом контексте & означает ссылку-поэтому foo возвращает ссылку на int, а не на int.
Я не уверен, что вы бы еще работали с указателями, но это аналогичная идея, вы на самом деле не возвращаете значение из функции - вместо этого вы передаете информацию, необходимую для поиска местоположения в памяти, где находится этот int.
Итак, чтобы подвести итог, вы не присваиваете значение вызову функции - вы используете функцию, чтобы получить ссылку, и затем присвоение значения, на которое ссылается новое значение. Легко думать, что все происходит одновременно, но на самом деле компьютер делает все в точном порядке.
Если вам интересно - причина, по которой вы получаете segfault, заключается в том, что вы возвращаете числовой литерал '2' - так что это точная ошибка, которую вы получите, если вы должны определить const int, а затем попытаться изменить его значение.
Если вы еще не узнали о указателях и динамической памяти, я бы рекомендовал что сначала есть несколько концепций, которые, я думаю, трудно понять, если вы изучаете их все сразу.
пример кода на связанной странице - это просто фиктивное объявление функции. Он не компилируется, но если бы у вас была определенная функция, она работала бы в целом. Пример означал "если бы у вас была функция с данной сигнатурой, вы могли бы использовать это".
в вашем примере
fooявно возвращает значение lvalue на основе подписи, но вы возвращаете значение rvalue, которое преобразуется в значение lvalue. Это явно означает провал. Вы могли бы сделать:int& foo() { static int x; return x; }и преуспел бы, изменив значение x, сказав:
foo() = 10;
функция, которую вы имеете, foo (), является функцией, которая возвращает ссылку на целое число.
Итак, скажем, первоначально foo вернул 5, а позже, в вашей основной функции, вы говорите
foo() = 10;, затем печатает foo, он будет печатать 10 вместо 5.Я надеюсь, что имеет смысл :)
Я тоже новичок в программировании. Интересно видеть такие вопросы, которые заставляют вас думать! :)
Comments