我有一些关于从函数返回对局部变量的引用的问题:
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
}
我的问题是=>
getA1()
的实施是否正确?
我觉得这是不正确的,因为它返回局部变量的地址或临时变量。
main
(1,2,3)中的哪些陈述会导致未定义的行为?
在const A& newA1 = getA1();
中,标准是否保证const引用的临时绑定在引用超出范围之前不会被销毁?
答案 0 :(得分:31)
1。
getA1()
实施是否正确?我觉得这是不正确的,因为它返回本地变量或临时的地址。
您的计划中唯一正确的getAx()
版本是getA3()
。无论你以后如何使用它们,其他两个都有不确定的行为。
2。 main(1,2,3)中的哪些语句会导致未定义的行为?
从某种意义上说,没有一个。对于1和2,未定义的行为是函数体的结果。对于最后一行,newA3
应该是编译错误,因为您无法将临时绑定到非const引用。
3。在
const A& newA1 = getA1();
中标准保证临时绑定const
在引用超出范围之前,引用不会被销毁?
没有。以下是一个例子:
A const & newConstA3 = getA3 ();
这里,getA3()
返回一个临时值,该临时值的生命周期现在绑定到对象newConstA3
。换句话说,临时将存在,直到newConstA3
超出范围。
答案 1 :(得分:4)
Q1:是的,这是一个问题,请参阅第二季的答案。
Q2:1和2是未定义的,因为它们引用了getA1和getA2堆栈上的局部变量。这些变量超出范围并且不再可用,并且随着堆栈不断变化,可能会覆盖更糟糕的变量。 getA3有效,因为创建了返回值的副本并将其返回给调用者。
问题3:没有这样的保证可以看到Q2的答案。
答案 2 :(得分:2)
我认为主要的问题是你根本没有回归临时工,你应该
return A(5);
而不是
A a(5);
return a;
否则,您将返回本地变量地址,而不是临时变量。临时的const引用仅适用于临时工。
我认为它在这里解释: temporary to const reference
答案 3 :(得分: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;
}