閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

にせものの for ループ

26日の日記の補足。会社の人から微妙に反響があったので。

あのループの何が「ホンモノ」なのかを説明するより、ニセモノの例を出した方が解りやすいと思うので、そちらから書いてみます。

例えば、とある std::vector (配列) の変数内の要素を全て舐めたい場合、次のようなコードを書くと思います。要素数は、size メソッドで取得します。

for(std::size_t i = 0; i < array.size(); ++i)
{
	// なんか処理
}

普通は、こんな実装をすると思います。しかし、この場合ループ中に毎回 size メソッドの呼び出しが起きますが、これは無駄なコストでしょう (もちろん、ループ中で要素数に変化がある場合はその限りではありませんが) 。実装によっては size メソッド一度の呼び出しに時間がかかる場合、パフォーマンスに影響も出てきます。

もしパフォーマンスに影響がある場合、 size メソッドの呼び出し回数を減らすために、変数を作成してあらかじめ値を保持しておくと思います。

std::size_t count = array.size();
for(std::size_t i = 0; i < count; ++i)
{
    // なんか処理
}

これで万事解決、のように思えますが、しかしこのコードにはひとつ問題があります。 count 変数が for 文を抜けても、この書き方だと使用できてしまいます。 C++ では変数のスコープは可能な限り短くするというのが基本なので、これは宜しくない。

とかくそんなわけで、最初の例も次の例も、見ていて気持ちの悪いコードでしたが、そんな気持ち悪さを払拭してくれたのが、先の「ほんものの for ループ」なのでした。

for(std::size_t i = 0, count = array.size(); i < count; ++i)
{                    ~~~~~~~~~~~~~~~~~~~~~~
	// なんか処理
}

for 文の最初の式で宣言した変数のスコープは、 for 文の中に限定されます*1ので、こうして count 変数も一緒に、最初に作成してやることで先にあげた不満を一挙解決することができると。

まさしく「本物」! ってことです。

ちなみに、今回例にあげた std::vector の size メソッドは大抵どの実装でもインライン展開されて関数呼び出しのオーバヘッドもかからないので、大して気にする必要も無かったりするんですけどね。

*1:古い C++ の仕様や VC6 の事は考えていません……