我知道C(cstring库)句柄中的memmove
重叠得很好,“以运行速度较慢为代价”(请参阅this post)。我想知道为什么要花费额外的运行时间?在我看来,可以通过向后复制而不是向前复制来解决任何重叠问题,我错了吗?
作为一个玩具示例,以下是“右移”功能的两个版本,该功能将数组的内容向右移动一个元素:
// Using memmove
template <typename T>
void shift_right( T *data, unsigned n )
{
if (n)
{
data[n-1].~T();
memmove( data+1, data, (n-1)*sizeof(T) );
new (data) T();
}
}
// Using copy_backward
template <typename Iterator>
void shift_right( Iterator first, Iterator last )
{
Iterator it = last;
std::copy_backward( first, --it, last );
}
它们相等吗?在性能方面,最好使用哪个?
注意:根据@DieterLücking的评论来判断,尽管采取了一些预防措施,但在这种情况下,使用
memmove
的上述版本并不安全。 最佳答案
假设实现良好,则memmove
唯一的“额外费用”是初始检查(加法和比较并分支),以确定是从头到尾复制还是从头到尾复制。此费用可以忽略不计(ILP隐藏加和比较,并且在正常情况下分支是完全可预测的),以致在某些平台上,memcpy
只是memmove
的别名。
预料到您的下一个问题(“如果memcpy的速度不比memmove快,为什么会存在?”),有一些很好的理由来保留memcpy
。在我看来,最好的是某些CPU实际上将memcpy实现为一条指令(例如,x86上的rep/movs
)。这些硬件实现通常具有首选的(快速)操作方向(或者它们可能仅支持一个方向的复制)。编译器可以用最快的指令顺序随意替换memcpy
,而无需担心这些细节。它对memmove
不能做同样的事情。