C ++中的“ int&foo()”是什么意思?


114

在阅读有关左值和右值的解释时,这些代码行向我伸出来:

int& foo();
foo() = 42; // OK, foo() is an lvalue

我在g ++中尝试过,但是编译器说“对foo()的未定义引用”。如果我加

int foo()
{
  return 2;
}

int main()
{
  int& foo();
  foo() = 42;
}

它可以很好地编译,但是运行它会产生分段错误。只是线

int& foo();

本身既可以编译又可以毫无问题地运行。

此代码是什么意思?如何为函数调用分配值,为什么它不是右值?


25
您没有为函数调用分配值,而是为其返回的引用分配了值。
弗雷德里克哈米迪

3
@FrédéricHamidi为返回的参考引用的对象分配一个值
MM

3
是的,它是对象的别名;引用不是对象
MM

2
@RoyFalk本地函数声明是一个痘,我个人很高兴看到它们从语言中删除。(不含当然lambda表达式)
MM

4
为此已经存在一个GCC错误
jotik 2016年

Answers:


168

该解释假定存在某种合理的实现,foo该实现将对value的左值引用返回int

这样的实现可能是:

int a = 2; //global variable, lives until program termination

int& foo() {
    return a;
} 

现在,由于foo返回左值引用,我们可以为返回值分配一些内容,如下所示:

foo() = 42;

这将a使用值更新全局42,我们可以通过直接访问变量或foo再次调用来检查该值:

int main() {
    foo() = 42;
    std::cout << a;     //prints 42
    std::cout << foo(); //also prints 42
}

像在operator []中一样合理吗?还是其他成员访问方法?
Jan Dorniak '16

8
考虑到对引用的混淆,最好从样本中删除静态局部变量。初始化会增加不必要的复杂性,这是学习的障碍。使其全球化。
Mooing Duck

72

所有其他答案都在函数内部声明了一个静态变量。我认为这可能会使您感到困惑,因此请查看以下内容:

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。如果您将初始化更改为a8,则将a更改为11。这是一些可能真正有目的的代码,与其他示例不同。


5
是否有理由写int a {3}而不是int a = 3?这种语法对我来说似乎不合适。
Aleksei Petrenko

6
@AlexPetrenko是通用初始化。我碰巧在方便的示例中使用了它。没什么不妥的
Kate Gregory

3
我知道这是什么 a = 3感觉好多了。个人喜好)
Aleksei Petrenko

就像在函数内部声明静态可能会使某些人感到困惑一样,我也相信使用通用初始化也是可能的。
ericcurtin

@AlekseiPetrenko如果int a = 1.3,则它隐式转换为a =1。而int {1.3}会导致错误:缩小转换范围。
Sathvik

32
int& foo();

声明一个名为foo的函数,该函数返回对的引用int。这些示例无法完成的工作就是为您定义可以编译的函数。如果我们使用

int & foo()
{
    static int bar = 0;
    return bar;
}

现在,我们有一个函数返回对的引用bar。因为bar是static在调用函数后仍然存在,所以返回对它的引用是安全的。现在,如果我们这样做

foo() = 42;

发生什么情况是我们将42分配给,bar因为我们将其分配给引用,而引用只是的别名bar。如果我们像这样再次调用该函数

std::cout << foo();

自从我们设置bar为上面的值后,它将打印42 。


15

int &foo();声明一个foo()带有返回类型的函数int&。如果在不提供主体的情况下调用此函数,则可能会得到未定义的引用错误。

在第二次尝试中,您提供了一个功能int foo()。与声明的函数的返回类型不同int& foo();。因此,您有两个相同的声明foo不匹配,这违反了“一个定义规则”,从而导致未定义的行为(无需诊断)。

对于某些可行的方法,请取出局部函数声明。如您所见,它们可能导致沉默的不确定行为。相反,只能在任何函数之外使用函数声明。您的程序可能如下所示:

int &foo()
{
    static int i = 2;
    return i;
}  

int main()
{
    ++foo();  
    std::cout << foo() << '\n';
}

10

int& foo();是返回对的引用的函数int。您提供的函数int没有参考就返回。

你可以做

int& foo()
{
    static int i = 42;
    return i;
}

int main()
{
    int& foo();
    foo() = 42;
}

7

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;
}

此代码打印:

$ ./a.out k = 5

因为foo()返回对全局变量的引用k

在修改后的代码中,您将返回的值强制转换为引用,然后该引用无效。


5

在这种情况下,&表示引用-因此foo返回对int而不是int的引用。

我不确定您是否已经使用过指针,但这是一个类似的想法,您实际上并未从函数中返回值-而是传递了在内存中查找位置所需的信息。整数是。

因此,总而言之,您不是在为函数调用分配值-您是在使用函数来获取引用,然后将被引用的值分配给新值。容易想到所有事情都会立即发生,但实际上计算机会按照精确的顺序进行所有操作。

如果您想知道-出现段错误的原因是因为您要返回数字文字“ 2”-因此,如果要定义const int然后尝试修改其常量,则会得到确切的错误值。

如果您还没有了解指针和动态内存,那么我建议您首先这样做,因为除非您立即学习所有概念,否则我认为有些概念很难理解。


4

链接页面上的示例代码只是一个虚函数声明。它不会编译,但是如果定义了某些功能,它将可以正常工作。该示例的意思是“如果您具有带有此签名的函数,则可以这样使用它”。

在您的示例中,foo显然是基于签名返回一个左值,但是您返回了一个转换为左值的右值。显然,这确定会失败。您可以这样做:

int& foo()
{
    static int x;
    return x;
}

并在更改时通过更改x的值而成功:

foo() = 10;

3

您拥有的函数foo()是一个返回对整数的引用的函数。

因此,假设最初foo返回5,然后在主函数中说foo() = 10;,然后输出foo,它将输出10而不是5。

我希望这是有道理的 :)

我也是编程新手。看到这样的问题使您思考很有趣!:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.