1

考虑foo函数

void foo(X x);

带有X矩阵 cass 和函数

X foobar();

假设我跑

foo(foobar());

在这种情况下,临时对象一步一步会发生什么?我的理解是

  1. foobar返回一个临时对象,比如说Xtemp1
  2. foo复制Xtemp1到它自己的临时对象,比如说Xtemp2,然后销毁Xtemp1
  3. foo在 上执行计算Xtemp2

另一方面,如果我foo超载

void foo(X& x);
void foo(X&& x);

那么情况会有所不同,特别是,

  1. foobar返回临时Xtemp1
  2. foo不会创建新的临时对象,而是Xtemp1通过其引用直接作用。

这张照片是否正确,或者如果不是,有人可以指出并纠正我的错误吗?非常感谢。

4

2 回答 2

2
foo(foobar());
  1. foobar的返回值是一个值,所以它是一个临时值。
  2. 1此函数会将返回值移动/复制到本地存储中以暂时使用。
  3. 1此函数会将本地存储中的值移动/复制到调用的参数中foo
  4. 调用foo执行。
  5. 2作为foo返回,它的参数被破坏。
  6. 2返回时foo,本地存储中的值被破坏。
  7. foobar的返回值被破坏。

1编译器可能会忽略这些移动/复制。这意味着这些复制/移动不必发生(任何值得使用的编译器都会忽略它们)。

2如果上面的移动/副本被省略,那么它们各自的变量的破坏自然是没有必要的。因为它们不存在。

另一方面,如果我将 foo 重载为

  1. foobar的返回值是一个值,所以它是一个临时值。
  2. 1此函数会将返回值移动/复制到本地存储中以暂时使用。
  3. 重载分辨率选择foo(X &&)调用。
  4. 使用本地存储值创建并初始化右值引用参数变量。
  5. 调用foo执行。
  6. 作为foo返回,它的引用参数被破坏(而不是它引用的值)。
  7. 2返回时foo,本地存储中的值被破坏。
  8. foobar的返回值被破坏。

请注意此处的主要区别。第 4 步和第 6 步不能省略。因此,如果X是一个像 一样的小类型int,那么函数将别无选择,只能创建一个对整数的毫无价值的引用。引用在内部实现为指针,因此编译器实际上不可能将其优化为寄存器。因此,本地存储必须在堆栈上,而不是在寄存器上。

因此,您将保证更少的移动/复制。但同样,任何体面的编译器都会忽略它们。所以问题是,X通常会太大而无法放入寄存器吗?

于 2013-05-14T08:33:36.200 回答
1

你的理解几乎是正确的。唯一的区别是,在第 2 步中,临时文件Xtemp1不会复制到任意命名的临时文件Xtemp2,而是复制到形式参数的空间x(来自声明foo(X x))。

此外,复制省略可能会起作用,这可能意味着 的返回值foobar()是直接在foo的形式参数的空间中构造的x,因此不会发生复制。这是标准允许的,但不能保证。

您对 r 值参考案例的看法是正确的。

于 2013-05-14T08:19:58.393 回答