これは何?
を見て、どんだけ違うの? と思って試してみた。
簡単なケース
n で受ける
c++
std::size_t sum1( std::vector<size_t> const & v ){
std::size_t sum=0;
for( std::size_t i=0, n=v.size(); i<n; ++i){
sum += i*v[i];
}
return sum;
}
毎回 .size()
を呼ぶ
c++
std::size_t sum2( std::vector<size_t> const & v ){
std::size_t sum=0;
for( std::size_t i=0; i<v.size(); ++i){
sum += i*v[i];
}
return sum;
}
比較してみた
これを、以下のコンパイラで -O2
でアセンブラを作って比較した。環境は macOS (intel)。
- Apple clang version 13.0.0 (clang-1300.0.29.30) / Target: x86_64-apple-darwin21.2.0
- g++-11 (Homebrew GCC 11.2.0) 11.2.0
結果は変わらず。
コンパイラは、ループ回数が変わらないことぐらいお見通し。
引数についてる const
を外しても同じ。
もっと面倒な例
ループ内で vector
を別の関数に const
参照で渡すんだけど、関数の実装は不明という場合。
n で受ける
c++
int foo( std::size_t x, std::vector<size_t> const & v );
int sum3( std::vector<size_t> & v ){
int sum=0;
for( std::size_t i=0, n=v.size(); i<n; ++i){
sum += foo(i,v);
}
return sum;
}
毎回 .size()
を呼ぶ
c++
int foo( std::size_t x, std::vector<size_t> const & v );
int sum4( std::vector<size_t> & v ){
int sum=0;
for( std::size_t i=0; i<v.size(); ++i){
sum += foo(i,v);
}
return sum;
}
比較してみた
先ほどと同じ環境で比較してみたら、両方とも差があった。
std::vector<size_t> const &
で要求している関数に渡してるんだから v.size()
は変わらないということになりそうだけど、コンパイラは const
修飾子を信用してないらしい。
まとめ
簡単な例しか調べてないけど、ループ内で vector を他の関数に渡したりしてなければ、コンパイラは要素数が変わらないことに気づくんじゃないかな。
一方。別の関数に vector の参照を渡すと、それが const 参照でもコンパイラは疑心暗鬼になって毎回 .size()
を呼ぶ。
まあ呼ぶっていっても関数呼び出しコードは作られなくて、メモリを参照するだけだけどね。