我知道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不能做同样的事情。

09-30 12:49
查看更多