2

ここ数日、C++ SDL をいじっていて、興味深い問題に遭遇しました。

SDL_Event event1;
while(SDL_WaitEvent(&event1))
{
    for(size_t i = 0; i < MainMenuOptions.size();i++)
    {
        if(event1.button.x > MainMenuOptions.at(i).GetX() && event1.button.x < (MainMenuOptions.at(i).GetX() + MainMenuOptions.at(i).GetWidth())  
        && event1.button.y > MainMenuOptions.at(i).GetY()  && event1.button.y < (MainMenuOptions.at(i).GetY() + MainMenuOptions.at(i).GetHeight()))
        {
            break;
        }
    }
}

for ループで break を使用すると、while ループではなく for ループから抜け出します。goto ステートメントを使用せずに while ループを抜け出すにはどうすればよいでしょうか? (goto 文は悪いプログラミングだと聞いた)

4

5 に答える 5

11

一般的な解決策は、これを独自の関数に入れ、そこから戻ることです。

inline SDL_Event do_it()
{
    SDL_Event event;
    while(SDL_WaitEvent(&event))
        for(std::size_t i = 0; i < MainMenuOptions.size(); ++i)
            if(/*...*/)
                return event;
    return event; // or whatever else suits, I know too little about your code
}
于 2012-08-20T08:56:09.403 に答える
7

それには別の答えがあります。誰もが私に反対票を投じる前に、それを言うべきだと思います。変数を使用することは、確かに「良い」方法です。ただし、ループから飛び出すためだけに追加の変数を作成するのは、少しやり過ぎに思えますよね?

はい、今回gotoは完璧なソリューションです。あなたがそれを使って何をしているのかは完全に明らかです。別の変数を使用しておらず、コードは短く、保守可能で読みやすいままです。

ステートメントgoto is bad practiceは、コード フローを変更する唯一の方法であった BASIC 時代の名残りです。しかし、今では「よく知っている」ので、gotoまたは他の構造が悪いと言っても、それをカットすることはできません. それを使って解決しようとしている1 つの特定の問題にとっては悪いことかもしれません (そして、goto で解決しようとするほとんどの問題に当てはまります)。ただし、(ここのような) 適切な状況があれば、問題ありません。もちろん、ここで議論を始めたくはありません。Goto は非常に強力なツールのようなものです (大槌など)。それには用途があり、ツールが完全に悪いとは言えません。それは間違った方法でそれを使用しているユーザーです。

于 2012-08-20T08:18:14.527 に答える
4

最初のポイント: IMO、あなたはあまりにも多くのことを 1 つの場所にまとめようとしていて、理解するのがかなり難しいものになってしまいました.絶対に達成するはずです。

2 点目: 明示的なループを使用して標準コレクションを反復処理することは、通常は間違いです。これも例外ではありません。標準ライブラリには、ループと同じ基本的なことを達成するためのアルゴリズムが既に含まれています。自分で書き直すよりも、それを使用する方がよいでしょう。

template <class T>
bool in_range(T a, T b, T c) { 
    return (a > b) && (a < b+c);
}

class in_rect {
   point p;
public:
   in_rect(point const &p) : p(p) {}

   // Not sure of the type of objects in MainMenuOptions, so just T for now.
   // 
   bool operator()(T const &m) {
       return in_range(p.x, m.GetX(), m.GetWidth()) 
           && in_range(p.y, m.GetY(), m.GetHeight());
   }
};

SDL_Event event1;

while (SDL_WaitEvent(&event1))
    if (std::any_of(MainMenuOptions.begin(), MainMenuOptions.end(),
                    in_rect(event1.button))      
        break;

他の問題を修正すると、goto. 明示的に削除することを意図した措置は講じていませんが、他の問題が修正されると (特にループを適切なアルゴリズムに置き換える)、その使用はなくなりました。

コードの総行数の増加について先制的にコメントする必要があると思います。はい、コードの行数が増えています。それの何?本当に必要な場合は、同じ基本的なアプローチを使用できますが、in_rectandを定義する代わりにin_range、基本的には元のステートメントから条件を取得ifしてラムダに詰め込むだけです。私はラムダが C++ に追加されたことを非常に嬉しく思いますが、この場合、ラムダを使用することに興奮していません。goto. _

簡単に言えば、行数は何かを測定するのに適した方法ではありません。

于 2012-08-24T15:20:39.447 に答える
4

変数を使用して、終了する必要があることを示します。

bool exit_program = false;

while( !exit_program && SDL_WaitEvent(&event1) )
{
    for( /* ... */ )
    {
        exit_program = true;
    }
}
于 2012-08-20T08:15:12.287 に答える
-1

変数と を追加しないソリューションgoto:

while(SDL_WaitEvent(&event1))
{
    size_t i;
    for(i = 0; i < MainMenuOptions.size();i++)
    {
        if(/* ... */)
        {
            break;
        }
    }
    if (i < MainMenuOptions.size())
        break;
}
于 2012-08-20T08:38:09.000 に答える