考虑我们有一个按值返回的函数:
int func() {
int x = 10; // create local variable x with value of 5
return x; // create temporary copy of x which is returned, local variable x is destroyed
}
int main()
{
int y = func(); // temporary copy of x is copied to y, when it hits`;` the temporary object is destroyed
return 0;
}
如果我在上面的评论中所说的错误,请纠正我。
现在我们可以通过对它进行常量引用来延长临时对象的生命周期。
int main()
{
const int & y = func(); // now the temporary object (R-value) is not destroyed when it hits `;` thus the life time is lenghtened.
return 0;
}
问题是:由于我创建了一个应该被销毁的临时对象的常量引用,这是否意味着cout << &y << endl
将打印该临时对象的地址,因为引用只是“别名”?那些存储在内存中的临时对象(R值)在哪里(我使用了原始类型int但它可以是类)?
答案 0 :(得分:2)
正如评论中已经说明的那样,使const引用(或右值引用)指向临时值会将其生命周期延长到引用的那一周。
此外,存储在内存中的临时对象(R值)在哪里(i 使用了原始类型int但它可以是类)?
标准未规定。但是,您可以查看最常见的编译器,了解它们将执行的操作。从GCC开始,没有任何优化,你将得到
func():
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 10
mov eax, DWORD PTR [rbp-4]
pop rbp
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
call func()
mov DWORD PTR [rbp-12], eax
lea rax, [rbp-12]
mov QWORD PTR [rbp-8], rax
mov eax, 0
leave
ret
因此返回值被推入函数内部的EAX寄存器中,一旦返回,该值就被推送到main()的堆栈帧,就像在main函数中创建了变量一样。您将在其他编译器中找到类似的结果。当启用优化时,很明显会发生:编译器看到函数只返回一些常量值并完全忽略它:
func():
mov eax, 10
ret
.LC0:
.string "%i"
main:
sub rsp, 24
mov edi, OFFSET FLAT:.LC0
xor eax, eax
lea rsi, [rsp+12]
mov DWORD PTR [rsp+12], 10
call printf
xor eax, eax
add rsp, 24
ret
在这里,我添加了一些printf()调用,它将输出temporty s.t的地址。该计划并非完全无足轻重。 所以它创建了这个函数,但是没有打扰它,只是再次将10写入本地堆栈框架中的某个空间。如果您只是按值使用它,它将被放入寄存器,因为不需要地址。