最近、私は配列を反復処理する方法をすべて考えていて、どれが最も効率的か (そして最も効率的でないか) を考えていました。架空の問題と 5 つの解決策を書きました。
問題
要素数を持つint
配列が与えられた場合、すべての要素に任意の数を割り当てる最も効率的な方法は何でしょうか?arr
len
42
解決策 0: 明らかなこと
for (unsigned i = 0; i < len; ++i)
arr[i] = 42;
解決策 1: 逆に明らかなこと
for (unsigned i = len - 1; i >= 0; --i)
arr[i] = 42;
解決策 2: アドレスと反復子
for (unsigned i = 0; i < len; ++i)
{ *arr = 42;
++arr;
}
解決策 3: アドレスとイテレータを逆にする
for (unsigned i = len; i; --i)
{ *arr = 42;
++arr;
}
解決策 4: 狂気に対処する
int* end = arr + len;
for (; arr < end; ++arr)
*arr = 42;
推測
ほとんどの場合、明らかな解決策が使用されますが、添字演算子が のように書かれた場合と同様に、乗算命令になるのではないかと思い*(arr + i * sizeof(int)) = 42
ます。
逆のソリューションは、代わりに比較i
することで減算操作を軽減する方法を利用しようとします。このため、私はSolution 2よりもSolution 3を好みます。また、配列がキャッシュに格納されているため、前方にアクセスするように配列が最適化されていることを読みました。これは、ソリューション 1で問題を引き起こす可能性があります。0
len
Solution 4がSolution 2よりも効率が悪い理由がわかりません。ソリューション 2はアドレスと反復子をインクリメントしますが、ソリューション 4はアドレスのみをインクリメントします。
結局、これらのソリューションのどれを好むかわかりません。答えは、コンパイラのターゲット アーキテクチャと最適化設定によっても異なると思います。
これらのうち、どちらが好きですか?