“想要速度? 按价值传递“

如我错了请纠正我。 说我有:

struct X { std::string mem_name; X(std::string name) : mem_name(std::move(name)) {} ... }; struct Y { std::string mem_name; Y(const std::string &name) : mem_name(name) {} ... }; 

X的ctor中, name显然是传给X的任何参数的拷贝, X调用std::string ctor来初始化mem_name ,对吗?

我们称之为复制 – 然后移动X * ; 两个操作: 复制,移动

Y的ctor中, name是一个const ref,这意味着没有实际的元素副本,因为我们直接处理从Y的对象需要创build的地方传递的参数。 但是,我们复制name来初始化Y mem_name ; 一个操作: COPY 。 当然,它应该快很多(对我来说更可取)?

在Scott Meyer的GN13演讲中(围绕时间8:10和8:56),他谈到了“想要速度?按价值传递” ,我想知道在传递参数(或string是否有任何性能差异或损失)通过参考和传递价值“为了获得速度?

我意识到通过价值传递参数可能会很昂贵,特别是在处理大量数据时。

也许(很明显?)我从谈话中失去了一些东西?

“想要速度?按价值传递” (1)的想法是,有时候,副本可以被消除。 考虑到你的类XY ,考虑这个用例:

 // Simulating a complex operation returning a temporary: std::string foo() { return "a" + std::string("b"); } struct X { std::string mem_name; X(std::string name): mem_name(std::move(name)) {} }; struct Y { std::string mem_name; Y(const std::string &name): mem_name(name) {} }; int main() { X(foo()); Y(foo()); } 

现在让我们来分析两个施工案例。

X先。 foo()返回一个临时的,用来初始化对象的name 。 该对象然后移入mem_name 。 请注意,编译器可以直接name空间中应用Return Value Optimization并构造foo()的返回值(实际上甚至是operator+的返回值)。 所以没有复制实际发生,只有一个举动。

现在我们来分析一下Y foo()再次返回一个临时的参数name 。 现在没有“外部提供”的返回值空间,所以必须在自己的空间中构build并绑定到参考。 然后将其复制到mem_name 。 所以我们正在做一个副本,没有办法绕过它。

总之,结果是:

  • 如果传递一个左值,则XY都将执行一个副本(初始化namename Y ,初始化mem_namename Y )。 另外, X将执行一个移动(当初始化mem_name )。

  • 如果右值被传入, X可能只会执行一个移动,而Y必须执行一个副本。

一般来说,一个移动可能是一个操作,其时间要求与传递一个指针的时间要求相当(这是通过引用做的)。 所以实际上,对于左值, X不会比Y更差,对于右值更好。

当然,这不是一个绝对的规则,必须用一粒盐。 如有疑问,简介。


(1)该链路很容易暂时不可用,截至2014年11月11日,似乎已经断开(404)。 内容的副本(虽然有奇怪的格式)似乎可以在几个博客网站:

  • 在csdn.net上的博客
  • blogspot.cz上的博客

另外,原始的内容可能通过backback机器访问。

还要注意,这个话题总体上引起了很大的讨论。 使用谷歌search引擎,带来了很多后续和对抗点。 列举其中一个例子,有“想要速度?不要(总是)通过值”由SO成员juanchopanza

没有通用规则。 通过价值传递可以在C ++ 11中获得一些重大胜利,包括移动语义和副本删除。

如果你真的想要速度,请剖析你的代码。

如果你真的不介意在你的API中暴露非引用(这应该是一个内部的标志,你将复制/分配给定的对象),那么使用副本是可以的。

复制elision比移动快,如果它不能被消除(由于各种原因,如调用过长的依赖函数调用链),C ++保证移动语义。