将rvalue引用传递给const lvalue reference paremeter

Sve*_*ven 6 c++ rvalue lvalue const-reference c++11

我试图理解C++ 11 rvalue引用以及如何在我的代码中使用它们以获得最佳性能.

假设我们有一个类A,它有一个指向大量动态分配数据的成员指针.

此外,一种foo(const A& a)与类对象做某事的方法A.

我希望防止在将A对象A传递给函数时调用复制构造函数foo,因为在这种情况下它将执行底层堆数据的深层复制.

我测试了传递左值参考:

    A a;
    foo(a);
Run Code Online (Sandbox Code Playgroud)

并传递右值引用:

    foo(A());
Run Code Online (Sandbox Code Playgroud)

在这两种情况下都没有调用复制构造函数.

这是预期的还是由于我的编译器(Apple LLVM 5.1)的一些优化?这有什么说明吗?

Jos*_*eld 14

这是预料之中的.如果将参数传递给引用类型参数(无论是左值还是右值引用),则不会复制该对象.这是整个参考点.

你所拥有的困惑很常见.只有在按值传递对象时才会选择复制或移动构造函数.例如:

void foo(A a);
Run Code Online (Sandbox Code Playgroud)

将A对象传递给此函数时,编译器将根据您传递的表达式是左值还是右值表达式来确定是使用复制还是移动构造函数.

另一方面,以下函数都不会尝试调用复制或移动构造函数,因为没有构造对象:

void foo(A& a);
void foo(const A& a);
void foo(A&& a);
void foo(const A&& a);
Run Code Online (Sandbox Code Playgroud)

重要的是要注意,你应该很少(如果有的话)有任何理由编写一个除了移动构造函数/赋值运算符之外的函数,它接受一个右值引用.你应该在传递值和传递const左值参考之间做出决定:

  1. 如果您无论如何都需要函数内部对象的副本(可能是因为您想要修改副本或将其传递给另一个函数),请通过value(A)获取它.这样,如果给你一个左值,它就必须被复制(你无法避免这种情况),但是如果给你一个右值,它将被最佳地移动到你的函数中.

  2. 如果您不需要该对象的副本,请通过const左值引用(const A&)获取它.这样,无论您是给出左值还是左值,都不会进行复制.当您确实需要复制它时,不应该使用它,因为它会阻止您使用移动语义.

根据它的声音,你根本不会制作任何副本,所以const A&参数可以正常工作.