Rvalue在引擎盖下引用

时间:2013-05-14 08:01:36

标签: c++ c++11 rvalue-reference

考虑foo函数

void foo(X x);

X矩阵cass和函数

X foobar();

假设我跑

foo(foobar());

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

  1. foobar会返回一个临时对象,例如Xtemp1;
  2. fooXtemp1复制到自己的临时对象,比如Xtemp2,然后销毁Xtemp1;
  3. fooXtemp2执行计算。
  4. 另一方面,如果我将foo重载为

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

    然后图片会有所不同,特别是

    1. foobar返回临时Xtemp1;
    2. foo不会创建新的临时文件,而是通过其引用直接作用于Xtemp1
    3. 这张照片是否正确,如果没有,有人可以指出并修正我的错误吗?非常感谢你。

2 个答案:

答案 0 :(得分:2)

foo(foobar());
  1. foobar的返回值是一个值,因此它是一个临时值。
  2. 1 此函数会将返回值移动/复制到本地存储中以供临时使用。
  3. 1 此函数会将本地存储中的值移动/复制到调用foo的参数中。
  4. foo的调用执行。
  5. 2 foo返回时,它的参数被破坏。
  6. 2 foo返回时,本地存储中的值将被破坏。
  7. foobar的返回值被破坏。
  8. 1 编译器可以省略这些移动/复制。这意味着不必发生这些复制/移动(任何值得使用的编译器都会忽略它们。)

    2 如果省略上面的移动/复制,则自然不需要销毁它们各自的变量。因为它们不存在。

      

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

    1. foobar的返回值是一个值,因此它是一个临时值。
    2. 1 此函数会将返回值移动/复制到本地存储中以供临时使用。
    3. 重载决策选择foo(X &&)进行呼叫。
    4. 使用本地存储值创建并初始化rvalue-reference参数变量。
    5. foo的调用执行。
    6. foo返回时,它的引用参数被破坏(不是它引用的值)。
    7. 2 foo返回时,本地存储中的值将被破坏。
    8. foobar的返回值被破坏。
    9. 请注意这里的主要区别。第4步和第6步不能被删除。因此,如果X是一个像int这样的小类型,那么该函数别无选择,只能创建一个对整数毫无价值的引用。引用在内部实现为指针,因此编译器实际上不可能仅将其作为寄存器进行优化。因此,本地存储必须是在堆栈而不是寄存器。

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

答案 1 :(得分:1)

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

此外,copy-elision可能会启动,这可能意味着foo(X x)的返回值直接在foobar()的形式参数foo的空间中构建,因此不会发生复制。这是标准允许的,但不能保证。

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