【问题标题】:Efficiency of std::copy vs memcpy [duplicate]std::copy 与 memcpy 的效率 [重复]
【发布时间】:2011-11-09 07:12:43
【问题描述】:

使用memcpy 和std::copy 之间的效率损失有多严重?

我的系统上的向量实现似乎没有使用连续内存,这使我不得不稍后 std::copy 其内容,而不是执行 memcpy(dest, &vec[0], size);。我不确定这会对效率造成多大的影响。

【问题讨论】:

  • 你使用的是什么实现? (C++03 保证连续存储)。
  • 难道标准的要求向量使用连续内存,所以它们的地址可以传递给需要数组的函数吗?
  • 如果您的向量数据不连续,那么您的实现不符合标准。
  • @Kerrek :我记得,两个主要的变化是创建默认初始化和值初始化之间的区别。
  • @Kerrek - C++98 没有说明向量是否连续。大多数人都认为无论如何都会如此。

标签: c++ performance stl


【解决方案1】:

std::copy 将在适当的时候使用memcpy,所以你应该只使用std::copy 并让它为你工作。

【讨论】:

  • std::copy 更有可能调用memmove 而不是memcpy,因为std::copy 的范围是允许重叠的,如果它们不重叠,这并不总是可以静态验证的。跨度>
  • 检查:printf '#include <algorithm>\nvoid DoCopy( char* o, const char* i, std::size_t count ) { std::copy( i, i + count, o ); }' | gcc -S -O3 -o - -std=c++98 -x c++ - 在我的系统上提供jmp memmove。
  • @Charles 是对的,STL 不能决定在编译时使用memcpy,因为不能保证范围不会重叠。
  • @Charles:在 VC2010 上相同。而且我还检查了,如果您使用两个向量并执行std::copy(src.begin(), src.end(), dest.begin()),它最终也会调用memmove。特别是它内联到call __imp__memmove。
【解决方案2】:

在可能的情况下(即元素类型是 POD),一个相当不错的实现将 std::copy 编译为调用 memmove。

如果您的实现没有连续存储(C++03 标准要求它),memmove 可能比std::copy 快​​,但可能不会太多。只有当你有测量结果表明它确实是一个问题时,我才会开始担心。

【讨论】:

  • 一个合理的实现更有可能使用memmove。为了能够安全地使用memcpy,需要在编译时满足更严格的条件。
  • @JerryCoffin:不正确。您可以使用std::copy 在内存中向后移动范围,使用std::copy_backward 向前移动范围。 (我承认,这有点不直观。)
  • §25.2.1/3:“要求:结果不得在 [first, last) 范围内。”
  • result,而不是 result + k 范围内的任何 k。如果这个限制意味着没有重叠,那么copy_backward(同样受到限制)将没有什么价值。
  • @Charles:说得好。我的立场是正确的。
【解决方案3】:

虽然您已经得到了许多好的答案,但我觉得有必要再补充一点:即使代码在理论上效率较低,也很少可能产生任何真正的影响。

原因很简单:在任何情况下,CPU 都比内存快得多。即使是相对糟糕的代码仍然很容易使 CPU 和内存之间的带宽饱和。即使所涉及的数据在缓存中,通常仍然是正确的 - 并且(再次)即使使用蹩脚的代码,移动也将完成得太快,无论如何都无法关心。

相当多的 CPU(例如,Intel x86)在硬件中有一条特殊的路径,在任何情况下都将用于大多数移动,因此实现之间的速度通常没有差异即使在汇编代码级别,这似乎也有很大不同。

最终,如果您关心在内存中移动事物的速度,您应该更担心消除它而不是让它更快。

【讨论】:

  • +1:完全正确。唯一会产生影响的地方是如果您没有编译优化(在这种情况下,对 std::copy 的调用不会被优化掉,但在这种情况下,您为什么担心性能?),如果使用 @987654323 @ 会给出错误的结果(在这种情况下,无论如何你都应该使用memmove),或者如果memmove 确定使用memcpy 是否安全的一点点旋转会压倒内存副本本身(其中如果你正在复制一点点内存)。
  • 即使代码在理论上效率较低,它也几乎不可能产生任何真正的影响 至少在 2001 年根本不是这种情况,在许多嵌入式架构上它是仍然不是这样。例如,参见Mike Wall's "Using Block Prefetch for Optimized Memory Performance"。差异可能很大(比简单代码快 3 倍)。
  • @KubaOber:您是否有充分的理由相信这些机器上的标准库使用了特别幼稚的代码(或者至少 memmove 使用比 std::copy 更好的代码)?
  • 我理解你的意思的方式是,基本上,任何代码都会“足够好”。在现代“主流”英特尔芯片上,它可能已经足够好了,其中对于非平凡大小的块,memcpy 的简单 K&R C 实现会使内存饱和,给定最近的编译器。只要你不是最新最好的,事情就会变得“有趣”。
猜你喜欢
  • 1970-01-01
  • 2013-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-19
  • 1970-01-01
  • 2011-06-10
  • 1970-01-01
相关资源
最近更新 更多