45

我对从函数返回对局部变量的引用有一些疑问:

class A {
public:
    A(int xx)
    : x(xx)
    {
        printf("A::A()\n");
    }
};

const A& getA1()
{
    A a(5);
    return a;
}

A& getA2()
{
    A a(5);
    return a;
}

A getA3()
{
    A a(5);
    return a;
}

int main()
{
    const A& newA1 = getA1(); //1
    A& newA2 = getA2(); //2
    A& newA3 = getA3(); //3
}

我的问题是=>

  1. 执行是否getA1()正确?我觉得这是不正确的,因为它返回的是局部变量或临时变量的地址。

  2. (1,2,3)中的哪些语句main会导致未定义的行为?

  3. 标准是否保证在const A& newA1 = getA1();引用超出范围之前不会破坏由 const 引用绑定的临时绑定?

4

4 回答 4

38

1.getA1()执行是否正确?我觉得这是不正确的,因为它是返回局部变量或临时的地址。

在您的程序中唯一正确的版本getAx()getA3(). 无论您以后如何使用它们,其他两个都有未定义的行为。

2. main (1,2,3) 中的哪些语句会导致未定义的行为?

从某种意义上说,它们都没有。对于 1 和 2,未定义的行为是函数体的结果。对于最后一行,newA3应该是编译错误,因为您不能将临时对象绑定到非 const 引用。

3.const A& newA1 = getA1();标准是否保证引用的临时绑定const 在引用超出范围之前不会被破坏?

不,以下是一个例子:

A const & newConstA3 = getA3 ();

在这里,getA3()返回一个临时对象,该临时对象的生命周期现在绑定到 object newConstA3。换句话说,临时将存在,直到newConstA3超出范围。

于 2009-09-23T13:11:59.613 回答
5

Q1:是的,这是一个问题,请参阅 Q2 的答案。

Q2:1 和 2 未定义,因为它们引用 getA1 和 getA2 堆栈上的局部变量。这些变量超出范围,不再可用,更糟糕的是,随着堆栈不断变化,可能会被覆盖。getA3 有效,因为创建了返回值的副本并将其返回给调用者。

Q3:没有这样的保证可以看到 Q2 的答案。

于 2009-09-23T13:08:33.217 回答
2

我认为主要问题是您根本没有返回临时人员,您应该

return A(5);

而不是

A a(5);
return a;

否则,您将返回局部变量地址,而不是临时地址。并且临时到 const 引用仅适用于临时人员。

我认为它在这里解释: 临时到 const 参考

于 2009-09-23T13:12:30.463 回答
0

如果您将在 VC6 上编译它,您将收到此警告

******编译器警告(级别 1) C4172 返回局部变量或临时对象的地址 函数返回局部变量或临时对象的地址。函数返回时局部变量和临时对象都被销毁,所以返回的地址是无效的。******

在测试这个问题时,我发现了有趣的事情(给定的代码在 VC6 中工作):

 class MyClass
{
 public:
 MyClass()
 {
  objID=++cntr;
 }
MyClass& myFunc()
{
    MyClass obj;
    return obj;
}
 int objID;
 static int cntr;
};

int MyClass::cntr;

main()
{
 MyClass tseadf;
 cout<<(tseadf.myFunc()).objID<<endl;

}
于 2009-09-23T16:02:38.640 回答