试图了解如何返回对自动变量的引用

时间:2014-06-04 18:31:58

标签: c++

我试图理解为什么第二段代码编译得很好,因为第一段代码没有。

int & test(void) {
    int v = 0;
    return v;
}


int main(void){
    int & r = test();
    return 0;
}

我知道这不起作用,因为您无法将引用传递给将被删除的自动变量。在我看来,下面的代码应该有同样的问题,但它没有。

int & test1(int & x) {
    return x;
}

int & test2(void) {
    int x = 0;
    return test1(x);
}

int main(void){
    int & r = test2();
    return 0;
}

似乎中间函数正在解决问题。但为什么呢?

3 个答案:

答案 0 :(得分:6)

仅仅因为某些东西编译,并不意味着它有效......

两个"替代品" 都遭受同样的问题; main 中的r是一个悬空引用,它所引用的内容早已不复存在,使用它会导致未定义的行为


第一段摘录

在第一个例子中,编译器很容易看到你将一个引用返回给一个局部变量,这个(就像编译器知道的那样)并没有感觉..当引用到达 main 时,引用的实例将会死亡。

编译器是一个很好的冠军,并告诉你这个问题。

第二段摘录

在第二个示例中,您正在执行相同的操作,但在中间添加重定向。编译器有很多技巧,但是回溯每个可能的执行路径,看看开发人员是否通过间接返回对局部变量的引用,并不是其中之一。

编译器无法看到你是坏人,也无法就你不了解的问题发出警告。


结论

无论你怎么做,都返回对局部变量的引用是不好的。

答案 1 :(得分:3)

考虑一下编译器必须做些什么来捕捉你正在演示的问题。它必须查看test1的所有调用者,看看他们是否将它传递给本地。也许这很容易,但如果插入越来越多的中间函数会怎么样?

int & test1(int & x) {
    return x;
}

int & test2(int & x) {
    return test1(x);
}

int & test3() {
    int x = 0;
    return test2(x);
}

int main(void){
    int & r = test3();
    return r;
}

编译器不仅要查看test1的所有调用者,还要查看test2的所有调用者。它还必须通过test2(想象它比这里的例子更复杂)来查看它是否正在将任何自己的本地传递给test1。将其推断为一段真正复杂的代码 - 跟踪这类事情会非常复杂。编译器只能做很多事情来保护我们自己。

答案 2 :(得分:1)

这两个代码示例格式错误并且具有未定义的行为,因为退出函数后将删除本地对象。所以引用无效。

要理解第二个示例与第一个示例没有区别,您可以通过以下方式重写它(调用第二个函数的插入内容)

/*
int & test1(int & x) {
    return x;
}
*/
int & test2(void) {
    int x = 0;
/*    return test1(x);*/
    int &r = x;
    return r;
}

如您所见,示例之间没有任何区别。

要达到你想要的效果,你可以采取以下方式

int test() 
{
    int v = 0;
    return v;
}


int main()
{
    const int & r = test();
    return 0;
}