我正在尝试理解C ++ 11 rvalue references 以及如何在我的代码中使用它们以获得最佳性能。
假设我们有一个类A
,它有一个指向大量动态分配数据的成员指针。
此外,方法foo(const A& a)
使用类A
的对象执行某些操作。
当A
的对象传递给函数A
时,我希望阻止foo
的复制构造函数被调用,因为在这种情况下它将执行底层堆数据的深层复制。
我测试了传递左值参考:
A a;
foo(a);
并传递右值参考:
foo(A());
在这两种情况下,复制构造函数都是而不是调用。
这是预期的还是由于我的编译器(Apple LLVM 5.1)的一些优化?有没有关于这个的说明?
答案 0 :(得分:13)
这是预期的。如果将参数传递给引用类型参数(无论是左值还是右值引用),则不会复制该对象。这是整个参考点。
你所拥有的困惑很常见。只有在按值传递对象时才会选择复制或移动构造函数。例如:
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
左值参考(const
)进行。这样,无论您是否给出左值或左值,都不会发生任何副本。当你需要复制它时,你不应该使用它,因为它会阻止你使用移动语义。
根据它的声音,你根本不会制作任何副本,因此const A&
参数可以正常工作。