15

C++ の「名前付きループ イディオム」に関する記事を読みました: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Named_Loop

このイディオムを使用すると、次のように書くことができます。

named(outer) 
for(int i = 0 ; i < rows ; ++i) {

   named(inner) 
   for(int j = 0 ; j < cols ; ++j) {

        if(some_condition)
            break(outer);   // exit the 'outer' loop 

   }
}

このような構造は、Java などの多くの言語のコア機能として既に存在します。

記事によると、2 つの悪意のあるマクロを定義することにより、C++ で実装できます。

#define named(blockname) goto blockname; \
                         blockname##_skip: if (0) \
                         blockname:

#define break(blockname) goto blockname##_skip;

多くの人が の使用を追放したいと思っていることは知っていますgotobreak個人的には、非常にまれなケースで、特にネストされたループが必要な場合に役立つことがわかりました。このイディオムは、そのためのよりクリーンなソリューションのように思えますが、実際のコードで使用しても問題ありませんか?

記事の議論ページでは、以下を読むことができます:

「これはやめろ。地獄に落ちろ」

だから私の質問は次のとおりです。名前付きループイディオムを使用することの欠点は何ですか? それは危険ですか ?はいの場合、なぜですか?

おまけの質問:continue同様に名前付きを実装することは可能ですか? (構文を使用することはできないと思いnamed(...) for(...;...;...) {}ますが、誰が知っていますか?)

EDIT:私はあなたに同意します、キーワードを再定義するのは厄介です。#define breakLoop()代わりに使用するのはどうですか?

4

2 に答える 2

10

コメントで説明されているように、#definingbreakには問題があります。他のものを使用すると仮定しましょう。

これは危険だと今でも言いたい。これは (C++ プログラマーにとって) 非常に珍しいイディオムであるため、理解する可能性は低く、破壊的変更を行う可能性があります。同じことを達成するための驚くべき方法が少なく、したがって危険性が低い方法があることを考えると、私はそれをやめることをお勧めします.

ループを関数またはラムダに入れることを検討してください。returnその後、外側のループから抜け出すことができます。利点として、早期終了に関する情報を返すことができます。これは、外部コードに役立つ場合があります。

于 2012-06-12T23:01:55.280 に答える
2

これにはいくつかの問題があります。

まず、言語の予約語の 1 つと同じ名前のマクロを定義しています。コンパイラがそれについて不満を持っていなくても、エラーが発生しやすく、(少なくとも IMO では) 危険ではありません。

第二に、私はプログラムでラベルを作成することを常にためらっています。同じスコープで同じ名前の 2 つのラベルを誤って作成した場合、コンパイラはおそらく文句を言うでしょうが、コンパイラが生成するエラー メッセージは、プログラマがこれらのマクロを分析しない限り、おそらく簡単には理解できないでしょう (これは、余分な抽象化の目的を部分的に無効にします)。 .

おそらく私の主な問題は、マクロが通常の言語構文とは異なる何かを導入することです。行はセミコロンで終わらず、ブロックnamed(...)も続きません。{ ... }新しい構文を追加すると、開発者が混乱したり、誤って誤用したりする可能性があります。

全体として、私は名前付きループのアイデアが好きですが、これはマクロを使用して作成したいようなものではありません。これは、言語自体が実際に提供する必要があるメカニズムです。C または C++ を使用する場合、手動で作成したラベルとgoto. ほとんどの場合、マクロの背後で何が起こっているかを隠すよりも、明示する方がよいでしょう。

于 2012-06-12T23:00:29.700 に答える