last update: 2013/09/03

2006/02/17

forかwhileか

友人にスケートの話をしてたらスケートしたくなってきた。くるくるまわりたい。

ここ2、3年ぐらい、更新の素早さと内容のクオリティのバランスに悩んでてわりと更新の素早さを優先してた感じなんですが、あとから読んでみるとあんまり役にたたねーんですよ。てことで、もうちょいわかりやすく、より本質的なテクニカル駄文になるように行きたいと思います。KISS(Keep It Simple, Stupid!)っていい言葉ですね(今日知った)。

というわけで、今日の話はforかwhileかって話なんですけど、最近やりたいって言ってたLuaをちょっとさわったんですが、なにぶんLightweight Languageはほぼ経験ゼロなので全然しきたりとかがわからないのでとりあえずたいぷちゃんに適当にLL界の常識を教えてもらったりですが、そこでふとforかwhileかっていうことが気になった。

いや、直接的にはLuaには全然関係ない話で、やっぱC++の話なんですけど、たとえば、単純に15回ループしたいってときは

for(int i=0; i<15; ++i){
   powawa();
}

みたいに書きますよね。ANSI Cだとカウンタ変数iのスコープはforの中のみなので、これはいいんです。次に、イテレータを使ってコンテナの各要素に対してpowawa関数を呼び出したいとすると

for(std::list<MyObject>::const_iterator ite=myContainer.begin(); ite!=myContainer.end(); ++ite){
   powawa(ite);
}

みたいに書けるわけですが、kawazoel的にはこれは正直for文が長くて可読性落ちるんで(正直1行だと横に長すぎです)、んじゃしかたないからwhileつかって書くかーってことで、

std::list<MyObject>::const_iterator ite=myContainer.begin();
while(ite!=myContainer.end()){
   powawa(ite);
   ++ite;
}

みたいに書くんです。でも、最近気付いたんですけど、これだと、ただのループカウンタとして使ってるだけのイテレータがwhileの外でも有効なんですよね。当たり前といえば当たり前ですけど。

しかも、デバッグですぐ気付くとはいえ、whileの最後の++ite;を忘れまくるんです。さらに言えば、ループの中でcontinue;をしたりするときにイテレータのインクリメントわすれてひどい目に遭ってみたりとか。

と、かなりマジメに考えてみると、continueしようが何しようがちゃんとインクリメントされるfor文って便利なんだなーといまさら気がつきました。んでも、正直STLコンテナのイテレータを宣言したfor文って上に示したとおりすごく読みづらいんですが、さてどうしたもんでしょうか。

だからといってwhileの外にカウンタを置くのはカウンタを再利用しない限りかなり気持ち悪いってことに今更気がついたので(もー明日研究室行ったらイテレータをwhileで回してるコード全部直そうかっていう勢いです)、すごく困ってるんですが、解決案としては

  • whileのままで、カウンタ用のイテレータを宣言してるところからwhileが終わったところまでをブロックで囲んでみる
  • for文に書き換えて、for文自体を複数行で書いてみる
  • for文に書き換えて、イテレータをtypedefしてみる

あたりを思いついたんですが、スマートな解決法としてはどれがよさそうなもんなんでしょうか? あと、これでwhileを使わなくなるとwhileってホント使いどころないんですけど(do-whileしたいときくらい?)、そんなもんなんでしょうか?

うん、でも、普通によく考えたらfor_eachを使えばいいじゃんっていうのがホントの答えなのかもしれないんだけど、でもそのプロジェクトではboostは使わないことにしてるので、for_each使うたびに関数オブジェクト用意するの? みたいな面もあるんですよ(関数オブジェクトつくりまくりで名前空間をよごしたくないなぁとか)。

上の例だとpowawa関数をオブジェクトとしてわたせばいいだけだけど、中に普通に処理書いてるところは…。再利用できる関数オブジェクトならいくらでも作ってもいいとおもうんだけどねぇ。1カ所でしか使わない関数オブジェクトを量産してfor_eachを回すのはちょっと気が引けます。boostつかえばBoost.Lambdaで無名関数とかいけちゃうんですけど、これも記法が独特になるし…。

comments powered by Disqus