9

我试图了解 C++11右值引用以及如何在我的代码中使用它们以获得最佳性能。

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

此外,一种foo(const A& a)对 class 对象执行某些操作的方法A

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

我测试了传递左值引用:

    A a;
    foo(a);

并传递一个右值引用:

    foo(A());

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

这是预期的还是由于我的编译器(Apple LLVM 5.1)的一些优化?有这方面的规范吗?

4

1 回答 1

21

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

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

void foo(A a);

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

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

void foo(A& a);
void foo(const A& a);
void foo(A&& a);
void foo(const A&& a);

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

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

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

从它的声音来看,您根本不会制作任何副本,因此可以使用const A&参数。

于 2014-07-18T15:05:01.813 回答