2016-12-21 3 views
5

ポインタのイテレータptrの場合、std::fill_n(ptr, n, 0)memset(ptr, 0, n * sizeof(*ptr))と同じことを行うはずです(ただし、@ KeithThompsonのコメントはthis answerを参照してください)。memsetに対してstd :: fill_n(ptr、n、0)からどのようなパフォーマンスが期待できますか?

C++ 11/C++ 14/C++ 17モードのC++コンパイラでは、これらの条件を同じコードにコンパイルすることができますか?そして、/同じコードをコンパイルしないと、-O0とのパフォーマンスに大きな違いがありますか? -O3?

注:もちろん、答えのいくつか/ほとんどはコンパイラ固有のものかもしれません。私は1つか2つの特定のコンパイラだけに興味がありますが、答えを知っているコンパイラについて書いてください。

+1

FWIW MSVSはテンプレートマジックを使用して、コンテナー内でmemsetとmemcpyを使用できるかどうかを判断します。アルゴがそのように実装されているかどうかは確かではありませんが、それは彼らが持つと思う跳躍ではありません。それは両方の方法と測定をコード化していると言いました。それはあなたに最高の答えを与えるでしょう。 – NathanOliver

+0

@ChrisBeck:編集を参照してください。 – einpoklum

+0

@ NathanOliver:しかし、 - memsetも何らかの形で実装する必要がある関数です。 – einpoklum

答えて

5

答えは、標準ライブラリの実装によって異なります。

たとえば、MSVCには、入力しようとしているタイプに基づいてstd::fill_nの実装がいくつかあります。

char*またはsigned char*またはunsigned char*std::fill_nを呼び出し、それが直接の配列を埋めるためにmemsetを呼び出します。

inline char *_Fill_n(char *_Dest, size_t _Count, char _Val) 
{ // copy char _Val _Count times through [_Dest, ...) 
_CSTD memset(_Dest, _Val, _Count); 
return (_Dest + _Count); 
} 

あなたは別のタイプで呼び出した場合、それはループに記入します:

template<class _OutIt, 
class _Diff, 
class _Ty> inline 
_OutIt _Fill_n(_OutIt _Dest, _Diff _Count, const _Ty& _Val) 
{ // copy _Val _Count times through [_Dest, ...) 
for (; 0 < _Count; --_Count, (void)++_Dest) 
    *_Dest = _Val; 
return (_Dest); 
} 

あなたの特定のコンパイラと標準ライブラリの実装上のオーバーヘッドを決定するための最良の方法は、とのコードをプロファイリングするだろうが両方の呼び出し。

0

memsetが適切なすべてのシナリオ(つまり、すべてのオブジェクトがPOD)では、どのレベルの最適化を有効にしても、2つのステートメントが同等であることがわかります。

memsetが適切でないシナリオの場合、memsetを使用すると不正なプログラムが発生するため、比較が妥当ではありません。あなたが簡単なgodbolt(および多くの他)などのツールを使って自分自身で確認することができます

例えば、gcc6.2これら二つの機能には、最適化レベル-O3と文字通り同じコードを生成します。

#include <algorithm> 
#include <cstring> 

__attribute__((noinline)) 
    void test1(int (&x) [100]) 
{ 
    std::fill_n(&x[0], 100, 0); 
} 

__attribute__((noinline)) 
    void test2(int (&x) [100]) 
{ 
    std::memset(&x[0], 0, 100 * sizeof(int)); 
} 

int main() 
{ 
    int x[100]; 
    test1(x); 
    test2(x); 
} 

https://godbolt.org/g/JIwI5l

関連する問題