此问题来自Q& A here
我有一些疑问,我认为不能在那里的后续评论中被问到,并且不太确定我是否可以用疑惑编辑链接的问题......因此是一个新问题。
首先,我从相关问题中学到的是,将ref返回到本地就是EVIL!
现在,请考虑该问题中的相同示例,但稍微修改一下:
#include<iostream>
#include<stdio.h>
#include<string>
using namespace std;
class A
{
public:
int x;
string s;
A(int xx,string ss):x(xx),s(ss)
{
cout<<"A::A()"<<x<<","<<s<<"\n";
}
A(const A& that)
{
cout<<"cpy ctr\n";
x=that.x;
s=that.s;
}
A& operator=(const A& that)
{
cout<<"operator=\n";
}
~A()
{
cout<<"~A()"<<s<<"\n";
}
};
const A& getA1()
{
A a(1,"A1");
cout<<"returning from A1\n";
return a;
}
A& getA2()
{
A a(2,"A2");
cout<<"returning from A2\n";
return a;
}
A getA3()
{
A a(3,"A3");
cout<<"returning from A3\n";
return a;
}
int main()
{
A &newA2 = getA2(); //.....................LINE 2
cout<<"returned from A2\n";
cout<<"-----------------------------\n";
A newA3 = getA3(); //......................LINE 3
//A const newConstA3 = getA3 ();
cout<<"returned from A3\n";
cout<<"-----------------------------\n";
//cout<<"newA2="<<newA2.x<<","<<newA2.s<<"\n";
cout<<"newA3="<<newA3.x<<","<<newA3.s<<"\n";
}
输出如下..
A::A()2,A2
returning from A2
~A()A2
returned from A2
-----------------------------
A::A()3,A3
returning from A3
returned from A3
-----------------------------
newA3=3,A3
~A()A3
现在我怀疑......
,在破坏临时值后,有趣getA2()
(由ref返回)返回,因此接收对象newA2
使用起来很危险。 (之所以我已经注释掉了它的用法。)那么为什么即使它通过“复制”返回,也为什么要执行有趣的getA3()
破坏临时(注意getA3()
内的临时析构函数不会被调用..only newA3
对象的析构函数在main()
}结束时被调用?我不知道那个临时去哪儿了?
现在,如果在 LINE 2 中我将其从A& newA2 = getA2();
更改为A newA2 = getA2();
,则会在此处调用复制ctr(最终会产生一个段落错误,因为指示对象具有死了),但为什么复制ctr在 LINE 3 被调用?如何将临时状态复制到对象newA3
中,注意没有调用operator=()
?
最后..这里的输出来自gcc,但MSVC ++ 2008的工作方式不同吗?
即使 LINE 3 中的代码A newA3 = getA3();
,它的行为与 LINE 2 相同,即在返回之前它会破坏临时值!任何线索?
答案 0 :(得分:2)
您似乎从Return Value Optimisation中受益。
因为您正在将一个(尽管是无效的)引用复制到一个新对象中。
MSVC和GCC大致相同。避免未定义的行为(这可能比它看起来更难),如果它们的工作方式不同,那么编译器就会出现错误。
答案 1 :(得分:0)
当然,要返回的值不会被销毁,否则您将永远无法从函数返回任何内容。我相信它在从本地范围复制后直接进入调用范围的堆栈。
复制elision。当副本过多时(就像在这里一样),编译器可以将它(即使它有副作用)作为一种标准规定的“优化”。关于SO的许多问题都记录了这一点。
目前尚不清楚你在问什么。您没有显示两个要比较的输出。