2

C ( memmovecstring ライブラリ) では、ハンドルが適切にオーバーラップすることを理解してます。なぜこの追加のランタイム コストがかかるのだろうと思っていました。オーバーラップの問題は、前方ではなく後方にコピーすることで修正できるように思えますが、間違っていますか?

おもちゃの例として、配列の内容を右に 1 要素だけシフトする「右シフト」関数の 2 つのバージョンを次に示します。

// 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は、この状況では安全ではありません。

4

4 に答える 4

7

実装が適切であると仮定すると、 の唯一の「追加コスト」memmoveは、前から後ろにコピーするか後ろから前にコピーするかを決定するための初期チェック (追加と比較分岐) だけです。このコストは完全に無視できる (加算と比較は ILP によって隠蔽され、通常の状況では分岐は完全に予測可能です) ため、一部のプラットフォームでmemcpymemmove.

次の質問 (「memcpy が memmove よりも大幅に高速でない場合、なぜ memcpy が存在するのですか?」) に備えて、いくつかの良い理由がありmemcpyます。私の考えでは、一部の CPU は基本的に単一の命令として memcpy を実装しています ( rep/movsx86 など)。これらの HW 実装には、多くの場合、優先 (高速) 方向の操作があります (または、一方向のコピーのみをサポートする場合があります)。コンパイラはmemcpy、これらの詳細を気にすることなく、最速の命令シーケンスに自由に置き換えることができます。に対して同じことはできませんmemmove

于 2014-03-03T21:44:29.390 に答える
2

コピーまたは移動する適切な方法は、std::copy、std::copy_n、std::copy_backward、および std::move です。適切な C++ ライブラリは、必要に応じて memcpy または memmove を使用します。したがって、コピーまたは移動されたシーケンスが自明なデータを保持していない場合、未定義の結果を求める必要はありません。

注: ここで、std::move はテンプレート 'OutputIterator move(InputIterator first, InputIterator last, OutputIterator result);' です。(@Voidの場合)

于 2014-03-03T22:22:45.737 に答える