我知道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
的上述版本是不安全的。
答案 0 :(得分:6)
假设一个好的实现,memmove
的唯一“额外成本”是初始检查(添加和比较和分支),以决定是从前到后还是从后到后复制面前。这个成本是完全可以忽略的(添加和比较将被ILP隐藏,并且分支在正常情况下是完全可预测的),在某些平台上,memcpy
只是memmove
的别名。
预期你的下一个问题(“如果memcpy没有明显快于memmove,为什么它存在?”),有一些很好的理由可以保持memcpy
。在我看来,最好的一个是,一些CPU实际上将memcpy实现为单个指令(例如,在x86上为rep/movs
)。这些HW实现通常具有优选(快速)操作方向(或者它们可能仅支持在一个方向上的复制)。编译器可以用最快的指令序列自由替换memcpy
,而不必担心这些细节;它不能对memmove
执行相同的操作。
答案 1 :(得分:2)
Memmove告诉你是否要向后或向前复制;它也针对此任务进行了高度优化(即尽可能多地在SSE优化块中进行复制)。
你不可能通过调用任何通用的STL算法做得更好(他们能做的最好的事情就是在幕后调用memcopy或memmove),但当然你只需运行你的代码和时间就可以回答这个问题。它
答案 2 :(得分:2)
来自您实际链接的帖子(强调我的):
memcpy只是循环,而memmove执行测试来确定哪个 循环方向以避免破坏数据。这些 实现相当简单。最高性能 实现更复杂(涉及复制字大小 一次阻止而不是字节。)
答案 3 :(得分:2)
复制或移动的适当方法是std :: copy,std :: copy_n,std :: copy_backward和std :: move。如果适用,正确的C ++库将使用memcpy或memmove。因此,如果复制或移动的序列不存在重要数据,则无需进行未定义的结果。
注意:这里std :: move是模板'OutputIterator move(首先是InputIterator,最后是InputIterator,OutputIterator结果);' (对于@Void)