我想知道如果我调用函数f(3),编译器如何保存这个临时int;
int f (int x) { return x; }
以及编译器将如何解决这个问题:
int a=f(3);
就像做一个int a = x; (我知道x已经被破坏了)或者它确实创建了一个名为f(3)的临时变量,就像这样int f(3)=x;
int& a=f(3);
为什么这不起作用?
答案 0 :(得分:6)
编译器将执行以下操作之一:
int a = 3
一样获得相同的程序集。引用变量,在代码中声明为int &a
的引用变量是“现有内存位置的不同名称”。因此,声明int &a
不会为任何地方的int
分配空间。它只是声明a
来引用已经分配的内存位置。
此位置可能是现有变量int b
,因此您说:
int b;
int &a = b;
此处,a
将引用b
引用的相同内容。 “现有对象的新名称”是一个很好的习惯用法。
你可以得到幻想并说出int &a = array[5]
,以便a
引用int
数组array
的第6个元素,或int &a = *(int*)0x12345678
来引用特定的记忆位置,但我很离题。
您的代码
int &a = 3;
无法工作,因为3
是一个临时对象,在执行语句后会被遗忘。要理解这个问题,请从根本上考虑这个问题:如果a
引用已经分配的内存位置,那么在执行语句int &a = 3
之后它会引用什么,并且不再有临时对象3
?
这也是函数中引用变量的常见问题:返回对函数本地对象的引用是未定义的行为......但我再次离题了。你总是必须有一个“活着的,分配的对象”供a
引用,故事的结尾。
像
这样的声明通常会发生什么int a = 3;
是编译器生成代码(简化):
重点是:在任何一种情况下,都没有为对象3
分配长期内存位置,因此实际上无法使int &a
引用此对象。< / p>
“长期存储位置”表示将通过分配操作的位置。在分配操作之后,存储3的寄存器将被覆盖并重新使用 ,因此它在理论上甚至不符合int &a
的目标(实际上,int &a
}无论如何,只能用来指代内存位置,而不是寄存器。)
答案 1 :(得分:1)
cdecl
(这是常见的),该函数将在EAX寄存器中返回x
。然后将其复制到分配给a
。当然,优化编译器会优化整个过程:
int x = 3;
2。您不能引用对象生命周期已结束的内容。 x
的对象生存期在函数执行时结束。
答案 2 :(得分:0)
任何合理的编译器都可以(并且会)转向
int a=f(3);
进入
int a=3;
调用最初会编译成类似于将返回地址压入堆栈,然后是参数;函数本身会编译弹出参数,弹出返回地址并再次推送参数,然后分支到返回地址。一个简单的优化器会检测到没有完成任何有用的工作,并优化整个过程。
答案 3 :(得分:0)
当调用函数f(3)时,调用语句的指令地址保存在寄存器中,指令指针跳转到函数f的第一个语句的地址。函数f的新堆栈帧也被压入堆栈。当函数调用返回时,将从f(3)为返回的int创建临时值,这是当你执行int x=f(3);
时将分配给x的内容(因此f中的返回值是在临时中创建的,然后是复制到x)所以是的,正在为返回创建临时。为f(3)创建的堆栈也被销毁。
int& a=f(3);
不能作为参考。 Reference是别名。别名适用于已存在的内容。 f(3)返回要分配给变量的临时副本。由于在f(3)调用之后堆栈将消失,你无法真正为其分配引用。
答案 4 :(得分:0)
int& a=f(3);
- 关于这一点的不好之处在于您正在创建对临时变量的引用。在函数退出时,引用所引用的数据已被清除,因此它现在是一个挂起引用。
在您概述的情况下,编译器可能只会将int a = f(3);
视为int a = 3;
,但您永远无法确定,因为最终这取决于特定的编译器以及它如何执行其优化。 / p>