2

考虑我们有一个按值返回的函数:

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 但它可能是类)?

4

1 回答 1

2

如评论中所述,将 const 引用(或右值引用)指向一个临时对象会将其生命周期延长到该引用之一。

那些临时对象(R值)存储在内存中的哪里(我使用原始类型 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

https://godbolt.org/g/8wPQqx

所以返回值被压入函数内部的 EAX 寄存器,一旦返回,该值被压入 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() 调用,它将输出临时 st 的地址,该程序并不完全是微不足道的。所以它创建了函数,但不会打扰调用它,只是再次将 10 写入本地堆栈帧中的某个空间。如果你只是按值使用它,它只会被放入一个寄存器中,因为不需要地址。

于 2017-10-28T18:48:35.110 回答