ゲーム エンジンのマイクロ最適化の状況: C++ 11 の範囲 for ループを使用vector<int>
して、auto
キーワードで , を反復処理しています。
より速いもの:
for(auto value : ints) ...
また
for(auto& value : ints) ...
?
ゲーム エンジンのマイクロ最適化の状況: C++ 11 の範囲 for ループを使用vector<int>
して、auto
キーワードで , を反復処理しています。
より速いもの:
for(auto value : ints) ...
また
for(auto& value : ints) ...
?
どちらが速いかを気にする前に、どちらが意味的に正しいかを気にする必要があります。反復される要素を変更する必要がない場合は、最初のバージョンを選択する必要があります。それ以外の場合は、2 番目のバージョンを選択する必要があります。
確かに、ベクトルの内容を変更する必要がない場合でも、への参照を使用するオプションがまだあることに異議を唱えることができますconst
。
for(auto const& value : ints)
そして、問題は次のようになります。どちらが速いですか? 参照const
または値による?
for
繰り返しますが、上記が意味的に正しいかどうかを最初に検討する必要があります。これは、ループ内で何をしているかによって異なります。
int i = 0;
for (auto const& x : v) // Is this correct? Depends! (see the loop body)
{
v[i] = 42 + (++i);
std::cout << x;
}
for (auto i : x)
これは、これが意味的に正しい場合はいつでも使用する基本的な型について述べています。
パフォーマンスが悪くなるとは思いません (むしろ良くなると思います) が、パフォーマンスに関してはいつものように、仮定を裏付ける唯一の有意義な方法は、測定、測定、および測定することです。
変更value
して、ベクター内の実際の要素を変更することが期待される場合は、必要 auto&
です。変更しない場合は、 orvalue
を使用してまったく同じコードにコンパイルされる可能性があります(自分で調べるためにプロファイルします)。auto
auto&
QueryPerformanceCounter に基づくタイマーで VS2012 を使用してタイミングを計りました...
m::HighResTimer timer;
std::vector<int> ints(100000000, 17);
int count = 0;
timer.Start();
for(auto& i : ints)
count += i;
timer.Stop();
std::cout << "Count: " << count << '\n'
<< "auto& time: " << duration_cast<duration<double, std::milli>>(timer.Elapsed()).count() << '\n';
count = 0;
timer.Reset();
timer.Start();
for(const auto& i : ints)
count += i;
timer.Stop();
std::cout << "Count: " << count << '\n'
<< "const auto& time: " << duration_cast<duration<double, std::milli>>(timer.Elapsed()).count() << '\n';
count = 0;
timer.Reset();
timer.Start();
for(auto i : ints)
count += i;
timer.Stop();
std::cout << "Count: " << count << '\n'
<< "auto time: " << duration_cast<duration<double, std::milli>>(timer.Elapsed()).count() << '\n';
結果....
Count: 1700000000
auto& time: 77.0204
Count: 1700000000
const auto& time: 77.0648
Count: 1700000000
auto time: 77.5819
Press any key to continue . . .
ここでは時差を読みません。すべての実用的な目的のために、それらは同一であり、実行ごとにわずかに変動します。
GCC では、両方のバージョンが を-O1
介して最適化フラグを使用して同じアセンブリにコンパイルされ-O3
ます。
コンパイラが最適化をfor (auto value : ints)
処理するので、値を変更する必要がないときはいつでも を使用します。Andy が指摘しているように、const-ref を使用することもできますが、パフォーマンスがまったく向上しない場合は、気にしません。
まず第一に、値を変更する場合は使用しauto&
、変更しない場合は使用しないでください。勝手に変えてしまう可能性があるからです。
const auto&
ただし、と シンプルの間で選択できる場合がありますauto
。の場合、ここではパフォーマンスは問題ではないと思いますstd::vector<int>
。
使用する理由auto
vector
)使用する理由const auto&
どちらの場合も、何をするかを理解する必要があります。サイクルが何らかの形で範囲を変更するかどうかによって異なります。