0

do{...} while(0);

do{}while(0);の使用法。私のコーディングで使用されているのは、ネストされた条件文の if else を長く使用したくないためです。私は最終的に失敗した時点で休憩を取り、関数が少なくとも 1 回トラバースされたことを保証して、ループから抜け出します。

さて、問題はコード警告ツールにあり、do{...}while(0);の使用時に警告が表示されます。

ネストされた if(){} else{}の使用法は読みにくく、非常に複雑です。コードにデッドコードを持たせることができます。

ネストされた if(){} else{}を除外して do{} while(0); 、理解可能なロジックでコードを読みやすくするための他の方法を残しましたか。

if(status_of_funcA_ok != funcA())
{ //failure}
else if (status_of_funcB_ok != funcB())
{//failure}
else if (status_of_funcC_ok != funcC())
else
{//Great}

do{
   if(status_of_funcA_ok != funcA())
   break;
   if (status_of_funcB_ok != funcB())
   break;
   if (status_of_funcC_ok != funcC())
   break;

  }while(0);
4

5 に答える 5

5

ループの完全なロジックを関数に移動し、をdo while{0}に置き換えます。ループの代わりに関数を呼び出します。breakreturn

  1. 美しさを心配する必要はありません。
  2. コンパイラは、do while{0}.

さらに、モジュール性を少し追加することで、プログラムがもう少し読みやすくなる可能性があります。

いずれにせよ、これを行う前に、コンパイラが非常にペダンティックなモードになっていないかどうかを確認してください。これをオフにすることもできます。それは警告を取り除くかもしれません。

ss。

PS:関数の戻り値は必要ないようですが、どの関数が成功したかの手がかりを得るためにそれを持つことができます。

于 2012-07-11T06:24:11.380 に答える
2

私もこのパターンを使用しています。不思議に思う人のために、ここに抽象的な例を示します。

do   // while(0) for break
{ 
  state1 = 0;
  if (cond1())
  {
    if (cond2())
      break;
    state1 = opA();
  }

  if (cond3() || state1 && state1->cond4())
    break;
  ... 
  Triumph(state1, ...);
  // often here: return
}
Failure(state1, ...);

これは、次の状況で有効だと思います。

  • あなたは長いシーケンスを持っています(たとえば、>〜半ダースの条件)
  • 条件が複雑で、重要な状態を使用/構築するため、要素を関数に分離することはできません
  • 例外に適していない環境にいるか、break-ing コード パスが実際には例外ではありません

それについてあなたができること:

警告を黙らせます。結局のところ、これは単なる警告です。この警告によってキャッチされる「典型的な間違い」(条件の代わりに 0 を入力するなど) は見当たりません。

[編集] さて、それはばかげていました。警告でキャッチする典型的な間違いは、 .[/edit]while (a1!=a1)ではなく、たとえばです。while (a1!=a2)

関数に分割し、状態をクラスに移動します。
これにより、上記のコードが次のように変換されます。

struct Garbler
{
  State1 state1;

  bool Step1()
  {
     state1 = 0;
     if (cond1())
     {
        if (cond2())
          return false;
        state1 = opA();
     }
     return true;
  }

  bool Step2()
  {
     return cond3() || state1 && state1->cond4();
  }
  .. 

  void Run()
  {
    if (Step1() && Step2() && ... && Step23())
      Triumph(state1, ...);
    else
      Failure(state1, ...);
  }
}

これは間違いなく読みにくく、さらに悪いことに、シーケンスを分解すると、非常に疑わしいクラス (メンバーが特定の順序でのみ呼び出される可能性がある) につながる可能性があります。

Scopeguards
これにより、ブレークを早期のリターンに変換できる場合があり、より受け入れられます。

state1 = 0;
ScopeGuard gFailure = MakeGuard(&Failure, ByRef(state1), ...);
if (cond1())
{
   if (cond2())
     return;
   state1 = opA();
}

if (cond3() || state1 && state1->cond4())
  return;

// everything went ok, we can dismiss the scopeguard
gFailure.Dismiss();
Triumph(state1, ...);

それらは C++0x でよりエレガントに記述でき、フローを維持できますが、ソリューションはそれほど柔軟ではありません。たとえばFailure()、単一の関数に簡単に分離できない場合などです。

于 2012-07-11T06:26:16.690 に答える
1

ネストされたネストされた if-else ステートメントは非常に読みにくくなる可能性がありますが、 do {..} while(0); を使用すると思います。交換ははるかに悪いでしょう。これは非常に型破りで、これを読んでいる人なら誰でも、if-else ステートメントと実際に関連付けることはないでしょう。

ネストされた if-else ステートメントを読みやすくするためにできることがいくつかあります。いくつかの提案は次のとおりです。

  1. ロジックを最適化する - ロジックを「リファクタリング」するときに、多くの if 句を省略できる場合があります。同一項目のグループ化。

  2. switch() を使用する - 通常、switch は if-else ステートメントよりも読みやすいです。各ケースに列挙型を関連付けることができ、これを切り替えることができます。

  3. 複雑なロジックを関数でカプセル化する

于 2012-07-11T05:39:47.813 に答える
1

gotoの代わりに使用できます。ただし、これは読みにくく、良い習慣でもありません。特定のケースごとに、深い if/else 構造を回避するためのより良い方法があると思います。たとえば、関数呼び出しを使用すると役立つ場合があります。do {} while(0)break

たとえば、次の代わりに:

if(status_of_funcA_ok != funcA())
{ //failure}
else if (status_of_funcB_ok != funcB())
{//failure}
else if (status_of_funcC_ok != funcC())
else
{//Great}

あなたは書ける:

if (check_funcs() == 0) {
   great();
}

int check_funcs() {
   if (status_of_funcA_ok != funcA())
     return -1;
   if (if(status_of_funcB_ok != funcB())) 
     return -2;
   if (if(status_of_funcC_ok != funcC())) 
     return -3;
   return 0; /* great */
}

を使用できる場合もありますexit()

throw()また、C++ ではandを使用できますtry/catch

try {
   /* */
  throw (this error);
   /* */
  throw (that error);
} catch (this error) {
} catch (that error) {
}
于 2012-07-11T05:15:20.927 に答える
0

確認する条件が他にもある場合は、使用を避けてくださいif{} else{},

ベストプラクティスは if else 条件を置き換えることですswitch case

于 2012-07-11T05:38:01.883 に答える