336

私はC++講師の講義ノートを読んでいて、彼は次のように書いています。

  1. インデントを使用する//OK
  2. 演算子の優先順位に依存しない-常に括弧を使用する//OK
  3. 常に{}ブロックを使用してください-単一の行であっても// OKではありません、なぜ???
  4. 比較の左側にあるConstオブジェクト//OK
  5. >=0の変数にはunsignedを使用する//いいトリック
  6. 削除後にポインタをNULLに設定-二重削除保護//悪くない

3番目のテクニックは私にはわかりません:1行をaに配置することで何が得られ{ ... }ますか?

たとえば、次の奇妙なコードを考えてみましょう。

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

次のように置き換えます。

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;

最初のバージョンを使用する利点は何ですか?

4

24 に答える 24

520

iインクリメントするときにも変更してみましょうj

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
        i++;

大野!Pythonから来ているので、これは問題ないように見えますが、実際にはそうではありません。

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;

もちろん、これはばかげた間違いですが、経験豊富なプログラマーでさえも犯す可能性のある間違いです。

もう1つの非常に良い理由は、 ta.speot.isの回答で指摘されています。

私が考えることができる3番目ifのものはネストされたものです:

if (cond1)
   if (cond2) 
      doSomething();

ここで、満たされていないdoSomethingElse()ときに実行したいとしますcond1(新機能)。それで:

if (cond1)
   if (cond2) 
      doSomething();
else
   doSomethingElse();

elseは内部に関連付けられているため、これは明らかに間違っていifます。


編集:これはいくつかの注目を集めているので、私は私の見解を明確にします。私が答えていた質問は次のとおりです。

最初のバージョンを使用する利点は何ですか?

私が説明したもの。いくつかの利点があります。ただし、IMOの「常に」ルールが常に適用されるとは限りません。だから私は完全にサポートしていません

常に{}ブロックを使用します-単一の行であっても//OKではありません、なぜ???

いつも{}ブロックを使うと言っているわけではありません。それが十分に単純な条件と動作である場合は、しないでください。誰かが後でやって来て、機能を追加するためにコードを変更する可能性があると思われる場合は、そうしてください。

于 2012-08-30T08:51:43.637 に答える
332

{とを使用しない場合、コメント付きの制御フローを誤って変更することは非常に簡単です}。例えば:

if (condition)
  do_something();
else
  do_something_else();

must_always_do_this();

1行のコメントでコメントアウトするdo_something_else()と、次のようになります。

if (condition)
  do_something();
else
  //do_something_else();

must_always_do_this();

コンパイルされますが、must_always_do_this()常に呼び出されるとは限りません。

この問題はコードベースにあり、リリース前に誰かが一部の機能をすぐに無効にしてしまいました。幸い、コードレビューでそれを見つけました。

于 2012-08-30T08:52:58.373 に答える
60

講師の能力に疑問があります。彼のポイントを考慮して:

  1. わかった
  2. 誰かが本当に書く(または読みたい)(b*b) - ((4*a)*c)でしょうか?いくつかの優先順位は明らかであり(またはそうあるべきです)、余分な括弧は混乱を助長します。(一方、括弧が不要であることがわかっている場合でも、あまり目立たない場合は括弧を使用する必要があります。)
  3. ある種。条件文とループのフォーマットには、2つの広く普及した規則があります。
    if(cond){
        コード;
    }
    
    と:
    if(cond)
    {{
        コード;
    }
    
    最初に、私は彼に同意します。開口部{はそれほど見えないので、常にそこにあると想定するのが最善です。ただし、2番目の例では、私(および私が一緒に仕事をしたほとんどの人)は、1つのステートメントの括弧を省略しても問題ありません。(もちろん、インデントが体系的であり、このスタイルを一貫して使用していることを条件とします。(そして、非常に読みやすいコードを記述している多くの非常に優れたプログラマーは、最初の方法でフォーマットする場合でも中括弧を省略します。)
  4. いいえ。のようなものif ( NULL == ptr )は、読みやすさを妨げるほど醜いです。直感的に比較を書いてください。(多くの場合、右側の定数になります。)彼の4は悪いアドバイスです。コードを不自然にするものは、コードを読みにくくします。
  5. いいえ。それ以外intは特別な場合のために予約されています。経験豊富なCおよびC++プログラマーにとって、unsignedシグナルビット演算子の使用。C ++には、実際のカーディナルタイプ(またはその他の効果的なサブレンジタイプ)はありません。unsignedプロモーションルールのため、数値では機能しません。シリアル番号のように、算術演算が意味をなさない数値は、おそらくunsigned。ただし、間違ったメッセージを送信するため、これに反対します。ビット演算も意味がありません。基本的なルールは、整数型はint、別の型を使用する重要な理由がない限り、ということです。
  6. いいえ。これを体系的に行うことは誤解を招く恐れがあり、実際には何も保護しません。厳密なオブジェクト指向コードでdelete this;は、多くの場合、が最も頻繁に発生します(そして、に設定thisすることはできませんNULL)。それ以外の場合、ほとんどdeleteはデストラクタであるため、後でポインタにアクセスすることはできません。また、に設定してNULLも、他のポインタが浮かんでいることはありません。ポインタを体系的に設定してNULL、誤った安心感を与え、実際には何も購入しません。

一般的なリファレンスのいずれかのコードを見てください。たとえば、Stroustrupは、最初のルールを除いて、指定したすべてのルールに違反します。

別の講師を探すことをお勧めします。彼が何について話しているのかを実際に知っている人。

于 2012-08-30T09:50:36.043 に答える
48

他のすべての答えはあなたの講師のルール3を擁護します。

私はあなたに同意します:ルールは冗長であり、私はそれをアドバイスしません。常に中括弧を追加すれば、理論的にはエラーを防ぐことができます。一方、私は実際にこの問題に遭遇したことはありません。他の答えが意味することとは反対に、必要になったら中括弧を追加することを一度も忘れていません。適切なインデントを使用すると、複数のステートメントがインデントされたら、中括弧を追加する必要があることがすぐに明らかになります。

「コンポーネント10」による回答は、これが実際にエラーにつながる可能性がある唯一の考えられるケースを実際に強調しています。しかし一方で、正規表現を介してコードを置き換えることは、とにかく常に多大な注意を払う必要があります。

次に、メダルの反対側を見てみましょう。常に中かっこを使用することに不利な点はありますか?他の答えは単にこの点を無視します。ただし、欠点があります。これは、垂直方向の画面スペースを大量に消費し、必要以上にスクロールする必要があるため、コードが読み取れなくなる可能性があります。

最初に多くのガード句がある関数を考えてみましょう(そうです、以下は悪いC ++コードですが、他の言語ではこれは非常に一般的な状況です):

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
    {
        throw null_ptr_error("a");
    }
    if (b == nullptr)
    {
        throw null_ptr_error("b");
    }
    if (a == b)
    {
        throw logic_error("Cannot do method on identical objects");
    }
    if (not a->precondition_met())
    {
        throw logic_error("Precondition for a not met");
    }

    a->do_something_with(b);
}

これは恐ろしいコードであり、次の方がはるかに読みやすいと強く主張します。

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
        throw null_ptr_error("a");
    if (b == nullptr)
        throw null_ptr_error("b");
    if (a == b)
        throw logic_error("Cannot do method on identical objects");
    if (not a->precondition_met())
        throw logic_error("Precondition for a not met");

    a->do_something_with(b);
}

同様に、短いネストされたループは、中括弧を省略することでメリットがあります。

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
        for (auto j = 0; j < a.h(); ++j)
            c(i, j) = a(i, j) + b(i, j);

    return c;
}

と比べて:

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
    {
        for (auto j = 0; j < a.h(); ++j)
        {
            c(i, j) = a(i, j) + b(i, j);
        }
    }

    return c;
}

最初のコードは簡潔です。2番目のコードは肥大化しています。

はい、前の行にオープニングブレースを配置することで、これをある程度軽減できます。したがって、中括弧を使用する場合は、少なくとも前の行に中括弧を配置してください。

つまり、画面スペースを占める不要なコードを記述しないでください。


最初に答えを書いたときから、私は一般的なコードスタイルをほとんど受け入れ、前の行に1つのステートメント全体を置くことができない限り、中括弧を使用しました。冗長な中括弧を使用しない方が通常は読みやすいと私はでも主張しており、これによって引き起こされるバグに遭遇したことはありません。

于 2012-08-30T12:17:12.387 に答える
41

私が取り組んでいるコードベースは、中かっこを病的に嫌う人々によってコードが散在しており、後でやってくる人々にとって、それは保守性に本当に違いをもたらす可能性があります。

私が遭遇した最も頻繁な問題のある例はこれです:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
    this_looks_like_a_then-statement_but_isn't;

ですから、私がやって来て、当時のステートメントを追加したいとき、注意しないと、簡単にこれになってしまう可能性があります。

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
{
    this_looks_like_a_then-statement_but_isn't;
    i_want_this_to_be_a_then-statement_but_it's_not;
}

中かっこを追加するのに約1秒かかり、デバッグの混乱を最小限に抑えることができるとすると、あいまいさを減らすオプションを使用しないのはなぜですか?私には誤った経済のように思えます。

于 2012-08-30T10:27:51.403 に答える
20

私の2c:

インデントを使用する

明らかに

演算子の優先順位に依存しない-常に括弧を使用する

「never」や「always」という言葉は使いませんが、一般的にはこのルールが役立つと思います。一部の言語(Lisp、Smalltalk)では、これは問題になりません。

常に{}ブロックを使用してください-単一の行であっても

私はそれをしたことはなく、問題も1つもありませんでしたが、特に学生にとってどのように役立つかはわかります。彼らが以前にPythonを勉強した場合。

比較の左側にあるConstオブジェクト

ヨーダ記法?いいえ、お願いします。読みやすさが損なわれます。コードをコンパイルするときは、最大の警告レベルを使用してください。

>=0の変数にはunsignedを使用します

わかった。おかしなことに、Stroustrupが同意しないと聞きました。

削除後にポインタをNULLに設定-二重削除保護

悪いアドバイス!削除されたオブジェクトまたは存在しないオブジェクトを指すポインタは絶対に使用しないでください。

于 2012-08-30T12:19:46.467 に答える
19

より直感的で簡単に理解できます。それは意図を明確にします。

また、新しいコードステートメントを追加しているときに{、新しいユーザーが知らないうちにを見逃した場合でも、コードが破損しないようにします。}

于 2012-08-30T08:52:24.557 に答える
14

上記の非常に賢明な提案に加えて、これが重要になるコードをリファクタリングしているときに遭遇した1つの例は、次のとおりです。非常に大きなコードベースを変更して、あるAPIから別のAPIに切り替えました。最初のAPIには、会社IDを次のように設定するための呼び出しがありました。

setCompIds( const std::string& compId, const std::string& compSubId );

一方、交換には2回の呼び出しが必要でした。

setCompId( const std::string& compId );
setCompSubId( const std::string& compSubId );

私はこれを正規表現を使用して変更することに着手しましたが、これは非常に成功しました。また、コードをastyleに渡したため、非常に読みやすくなりました。次に、レビュープロセスの途中で、条件付きの状況でこれが変更されていることを発見しました。

if ( condition )
   setCompIds( compId, compSubId );

これに:

if ( condition )
   setCompId( compId );
setCompSubId( compSubId );

これは明らかに必要なものではありません。置換を完全にブロック内として扱い、その後、間抜けに見えるものを手動で変更することによって、最初に戻る必要がありました(少なくともそれは正しくありません)。

astyle--add-bracketsには、角かっこがない場所に角かっこを追加できるオプションがあることに気付きました。以前と同じ位置にいる場合は、これを強くお勧めします。

于 2012-08-30T10:30:41.183 に答える
8

明らかないくつかのケースを除いて、私は{}どこでも使用しています。単一行はその1つです。

if(condition) return; // OK

if(condition) // 
   return;    // and this is not a one-liner 

戻る前にメソッドを追加すると、害を及ぼす可能性があります。インデントは、条件が満たされたときにreturnが実行されていることを示しますが、常に戻ります。

ステートメントを使用したC#の他の例

using (D d = new D())  // OK
using (C c = new C(d))
{
    c.UseLimitedResource();
}

これは

using (D d = new D())
{
    using (C c = new C(d))
    {
        c.UseLimitedResource();
    }
}
于 2012-08-30T13:44:46.483 に答える
8

私が考えることができる最も適切な例:

if(someCondition)
   if(someOtherCondition)
      DoSomething();
else
   DoSomethingElse();

どちらifelseペアになりますか?インデントは、外部ifがを取得することを意味しますがelse、実際にはコンパイラがそれを認識する方法ではありません。内側 ifはを取得し、else外側は取得ifしません。このコードが期待に応えられない理由を検査によって理解するには、それを知る必要があります(またはデバッグモードでそのように動作することを確認する必要があります)。Pythonを知っていると、さらに混乱します。その場合、インデントがコードブロックを定義することがわかっているので、インデントに従って評価されることが期待されます。ただし、C#は、空白についてのフライングフリップを提供しません。

とはいえ、私はこの「常に角かっこを使用する」という規則に特に同意しません。これにより、コードの垂直方向のノイズが非常に大きくなり、コードをすばやく読み取ることができなくなります。ステートメントが次の場合:

if(someCondition)
   DoSomething();

...それならこのように書くべきです。「常に角かっこを使用する」という表現は、「数学演算を常にかっこで囲む」ように聞こえます。それは非常に単純なステートメントa * b + c / dをに変え((a * b) + (c / d))、クローズパレン(多くのコーダーの悩みの種)を見逃す可能性をもたらします、そして何のために?操作の順序はよく知られており、十分に実施されているため、括弧は冗長です。a * (b+c) / dたとえば、括弧を使用して、通常適用される操作とは異なる順序の操作を実行するだけです。ブロックブレースも同様です。それらを使用して、デフォルトとは異なり、「自明」ではない場合に何をしたいかを定義します(主観的ですが、通常はかなり常識的です)。

于 2012-08-30T14:31:50.630 に答える
5

がないステートメントが2つ{}あると、問題を見逃しがちです。コードが次のようになっていると仮定しましょう。

int error = 0;
enum hash_type hash = SHA256;
struct hash_value *hash_result = hash_allocate();

if ((err = prepare_hash(hash, &hash_result))) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &client_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &server_random)) != 0)
    goto fail;
if ((err = hash_update(&hash_result, &exchange_params)) != 0)
    goto fail;
    goto fail;
if ((err = hash_finish(hash)) != 0)
    goto fail;

error = do_important_stuff_with(hash);

fail:
hash_free(hash);
return error;

見栄えがします。特にコードを含む関数がはるかに大きい場合、この問題は見逃しがちです。問題は、goto fail無条件に実行されることです。hash_updateこれがどれほど苛立たしいことかは簡単に想像できます(すべてが機能的に正常に見えるのに、なぜlastが常に失敗するのかを尋ねさせますhash_update)。

しかし、それは私がどこにでも追加することを意味するわけではありません{}(私の意見では、{}どこでも見るのは面倒です)。それは問題を引き起こす可能性がありますが、私の個人的なコーディングスタイルは、条件が同じ行にない場合を除いて条件を禁止しているため、私自身のプロジェクトでは決して起こりませんでした{}(はい、私のコーディングスタイルは型にはまらないことに同意しますが、私はそれが好きです、そして私は他のプロジェクトに貢献するときは、プロジェクトのコードスタイルを使用してください)。これにより、次のコードが正常になります。

if (something) goto fail;

しかし、次のものではありません。

if (something)
    goto fail;
于 2014-05-25T18:58:37.563 に答える
4

私はルチアンの受け入れられた答えが好きです。実際、私は彼が正しいという難しい方法を学びました。そのため、単一行のブロックであっても、常に中括弧を使用します。ただし、個人的には、例のように、フィルターを作成するときに例外を作成します。これ:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

私には散らかっているように見えます。実際にあなたの意図が単一のアクションである場合、forループとifステートメントを別々のアクションに分離します。2で割り切れるすべての整数をカウントします。より表現力豊かな言語では、これは次のように書くことができます。

j = [1..100].filter(_%2 == 0).Count

クロージャーがない言語では、フィルターを1つのステートメントで表現することはできませんが、forループの後にifステートメントを続ける必要があります。ただし、それはまだプログラマーの心の1つのアクションであり、次のようにコードに反映する必要があると思います。

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
  if (i % 2 == 0)
{
    j++;
}
于 2012-08-30T13:05:05.123 に答える
4

ループと条件付きブロックのスコープを明確に定義することで、コードを読みやすくします。また、偶発的なミスからあなたを救います。

于 2012-08-30T08:54:23.747 に答える
4

wrt 6:nullポインターを削除するのは無操作なので、より安全です。したがって、誤ってそのパスを2回通過した場合でも、メモリが破損して、空きメモリまたは他の何かに割り当てられているメモリが解放されることはありません。

これは、存続期間があまり明確ではなく、破棄された後に再作成されることが知られている静的ファイルスコープオブジェクトおよびシングルトンの問題のほとんどです。

ほとんどの場合、auto_ptrsを使用することで、これの必要性を回避できます。

于 2012-08-30T09:30:56.810 に答える
4

上記のエラーを防ぐための1つのオプションは、中かっこを使用しないときに発生したいことをインライン化することです。コードを変更しようとしたときにエラーに気付かないようにするのは非常に難しくなります。

if (condition) doSomething();
else doSomethingElse();

if (condition) doSomething();
    doSomething2(); // Looks pretty obviously wrong
else // doSomethingElse(); also looks pretty obviously wrong
于 2012-08-30T15:08:17.440 に答える
4

答えを見ると、私が習慣にしている種類の練習を明示的に述べている人は誰もいません。あなたのコードの話をします。

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

になる:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0) j++;
}

ifと同じ行j++にを置くと、 「このブロックをインクリメントしたいだけです」との人に通知する必要があります。もちろん、これは、行が可能な限り単純化されている場合にのみ価値があります。これは、ペリが言及しているように、ここにブレークポイントを設定してもあまり役に立たないためです。j

実際、私はJavaでこの「種類の」コードを含むTwitter Storm APIの一部に出くわしました。これは、このスライドショーの43ページにある実行コードからの関連スニペットです。

...
Integer Count = counts.get(word);
if (Count=null) count=0;
count++
...

forループブロックには2つのものが含まれているため、そのコードをインライン化することはしません。つまり決して

int j = 0;
for (int i = 0 ; i < 100 ; ++i) if (i % 2 == 0) j++;

それはひどいです、そして私はそれが(意図したように)機能するかどうかさえ知りません。これをしないでください。新しい行と中括弧は、散文でコンマやセミコロンを使用するのと同じように、別々であるが関連するコードを区別するのに役立ちます。上記のブロックは、いくつかの句と、別々の部分を区別するために中断したり一時停止したりすることのない他のステートメントを含む、非常に長い文と同じくらい悪いです。

本当に他の人に電報を送りたい場合は、三項演算子または?:フォームを使用する1行のみの仕事です。

for (int i = 0 ; i < 100 ; ++i) (i%2 ? 0 : >0) j++;

しかし、これはコードゴルフに集中しており、私は良い習慣ではないと思います(j ++を片側に置くべきかどうかは私にはわかりませ:ん)。注意:これまでC ++で三項演算子を実行したことはありません。これが機能するかどうかはわかりませんが、存在します

要するに:

あなたの読者(つまり、コードを管理している人)があなたのストーリー(コード)をどのように解釈するか想像してみてください。できるだけ明確にしてください。初心者のコーダー/学生がこれを維持していることを知っている場合は、{}混乱しないように、できるだけ多くの人を残してください。

于 2012-09-02T13:29:34.027 に答える
3

あなたがコンパイラーなら、それは何の違いもありません。どちらも同じです。

しかし、プログラマーにとって、最初のものはより明確で読みやすく、エラーが発生しにくいものです。

于 2012-08-30T08:55:13.347 に答える
3

中括弧を追加する別の例。バグを探していて、そのようなコードを見つけたら:

void SomeSimpleEventHandler()
{
    SomeStatementAtTheBeginningNumber1;
    if (conditionX) SomeRegularStatement;
    SomeStatementAtTheBeginningNumber2;
    SomeStatementAtTheBeginningNumber3;
    if (!SomeConditionIsMet()) return;
    OtherwiseSomeAdditionalStatement1;
    OtherwiseSomeAdditionalStatement2;
    OtherwiseSomeAdditionalStatement3;
}

メソッドを1行ずつ読むと、メソッドに条件があり、それが真でない場合に返されることに気付くでしょう。しかし実際には、いくつかの条件に基づいていくつかの変数を設定する100の他の単純なイベントハンドラーのように見えます。そしてある日、Fast Coderが登場し、メソッドの最後に変数設定ステートメントを追加します。

{
    ...
    OtherwiseSomeAdditionalStatement3;
    SetAnotherVariableUnconditionnaly;
}

その結果、SomeConditionIsMet()のときにSetAnotherVariableUnconditionnalyが実行されますが、すべての行のサイズがほぼ同じであり、戻り条件が垂直方向にインデントされている場合でもそれほど目立たないため、速い人は気づきませんでした。

条件付きリターンが次のようにフォーマットされている場合:

if (!SomeConditionIsMet())
{
    return;
}

それは非常に目立ち、FastCoderは一目でそれを見つけるでしょう。

于 2012-09-05T07:24:55.320 に答える
2

私は最初のものが明確であり、次に2番目のものであると考えています。それは命令を閉じる感覚を与えます、コードが複雑になったときは少しのコードで大丈夫{...}ですendifbegin...end

//first
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}


//second
int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;
于 2012-09-28T21:06:41.100 に答える
1

終了したら、ポインタをNULLに設定することをお勧めします。

理由の例を次に示します。

クラスAは次のことを行います。

  1. メモリのブロックを割り当てます
  2. その後、しばらくして、このメモリブロックを削除しますが、ポインタをNULLに設定しません。

クラスBは次のことを行います

  1. メモリを割り当てます(この場合、クラスAによって削除されたのと同じメモリブロックが割り当てられます)。

この時点で、クラスAとクラスBの両方に、同じメモリブロックを指すポインタがあります。クラスAに関する限り、このメモリブロックは終了しているため、存在しません。

次の問題を考えてみましょう。

クラスAに論理エラーがあり、その結果、現在クラスBに属するメモリに書き込む場合はどうなりますか?

この特定の例では、メモリアドレスが有効であるため、不正アクセス例外エラーは発生しません。その間、クラスAはクラスBデータを事実上破損しています。

クラスBは、予期しない値が発生した場合に最終的にクラッシュする可能性があります。クラッシュした場合、問題がクラスAにある場合、クラスBでこのバグを探すのにかなりの時間がかかる可能性があります。

削除されたメモリポインタをNULLに設定した場合、クラスAの論理エラーがNULLポインタに書き込もうとすると、すぐに例外エラーが発生します。

ポインタが2回目にNULLになったときに二重削除による論理エラーが心配な場合は、これにassertを追加します。

また、反対票を投じる場合は、説明してください。

于 2012-08-30T21:05:36.850 に答える
1

私はそれを常に単一の行に使用するとは限らないことを認めなければなりません{}が、それは良い習慣です。

  • 次のような角かっこなしのコードを記述するとします。

    for(int i = 0; i <100; ++ i)for(int j = 0; j <100; ++ j)DoSingleStuff();

jそして、しばらくして、ループに他のものを追加したいのですが、それを位置合わせによって行うだけで、角かっこを追加するのを忘れます。

  • メモリの割り当て解除が高速です。スコープが大きく、内部に大きな配列を作成するとします(newスタックされていない場合)。これらの配列は、スコープを離れた直後にメモリから削除されます。ただし、その配列を1つの場所で使用すると、しばらくの間スタックになり、ある種のゴミになる可能性があります。スタックのサイズは限られており、非常に小さいため、スタックサイズを超える可能性があります。したがって、場合によっては、それ{}を防ぐために書く方がよいでしょう。これは単一行ではなく、次のような状況であることに注意してください。

    if(...){// SomeStuff ... {// if、whileなどはありません。// SomeOtherStuff} // SomeMoreStuff}

  • それを使用する3番目の方法は2番目と同様です。スタックをきれいにするのではなく、いくつかの機能を開くためです。通常、長い関数で使用する場合はmutex、データにアクセスする直前と、データの読み取り/書き込みが終了した直後に、ロックとロック解除を行うことをお勧めします。この方法は、独自のメモリがある場合、またはメモリをロックする場合に使用classstructます。constructordestructor

  • さらに:

    if(...)if(...)SomeStuff(); else SomeOtherStuff(); // ifが2番目に移動しますが、alligmentはそれが最初にあることを示しています...

全体として、私は言うことはできませんが、常に{}単一の行に使用するための最良の方法は何ですか、それを行うことは悪いことではありません。

重要な編集 1行のコードブラケットをコンパイルしても何も起こりませんが、コードが解釈される場合は、コードの速度がわずかに低下します。非常にわずかです。

于 2013-07-30T08:09:22.267 に答える
1

常に中括弧を使用することは、非常に単純で堅牢なルールです。ただし、中かっこがたくさんあると、コードがエレガントに見えない場合があります。ルールで中括弧を省略できる場合は、より詳細なスタイルルールとより洗練されたツールが必要です。そうしないと、混沌とした紛らわしい(エレガントではない)コードが簡単に発生する可能性があります。したがって、使用されている他のスタイルガイドやツールとは別に単一のスタイルルールを探すことは、おそらく無益です。他の回答でも言及されていない、そのルール#3に関するいくつかの重要な詳細を紹介します。

最初の興味深い詳細は、その規則のほとんどの支持者がの場合にそれを違反することに同意するということですelse。言い換えれば、彼らはそのようなコードのレビューを要求しません:

// pedantic rule #3
if ( command == Eat )
{
    eat();
}
else
{
    if ( command == Sleep )
    {
        sleep();
    }
    else
    {
        if ( command == Drink )
        {
            drink();
        }
        else
        {
            complain_about_unknown_command();
        }
    }
}

代わりに、彼らがそれを見た場合、彼らはそれをそのように書くことを提案するかもしれません:

// not fully conforming to rule #3
if ( command == Eat )
{
    eat();
}
else if ( command == Sleep )
{
    sleep();
}
else if ( command == Drink )
{
    drink();
}
else
{
   complain_about_unknown_command();
}

elseとの間に中括弧がないため、これは技術的にその規則に違反しifます。ルールのこのような二重性は、無意識のツールを使用してコードベースに自動的に適用しようとすると表面化します。確かに、なぜ議論するのか、ツールにスタイルを自動的に適用させるだけです。

2番目の詳細(これもそのルールの支持者によって忘れられがちです)は、発生する可能性のあるエラーは、そのルール#3の違反だけが原因ではないということです。実際、それらはほとんどの場合、ルール#1の違反も伴います(誰も議論しません)。繰り返しますが、自動ツールの観点からは、ルール#1に違反したときにすぐに文句を言うツールを作成することは難しくないため、ほとんどのエラーをタイムリーにキャッチできます。

3番目の詳細(そのルールの反対者によって忘れられることが多い)は、単一のセミコロンで表される空のステートメントの紛らわしい性質です。ある程度の経験を持つほとんどの開発者は、遅かれ早かれ、セミコロンの置き忘れや、セミコロンだけを使用して記述された空のステートメントによって混乱しました。単一のセミコロンの代わりに2つの中括弧を使用すると、視覚的に簡単に見つけることができます。

于 2013-07-30T12:04:04.260 に答える
1

制御ステートメントを作成するには、いくつかの方法があります。それらの特定の組み合わせは、読みやすさを損なうことなく共存できますが、他の組み合わせは問題を引き起こします。スタイル

if (condition)
  statement;

制御ステートメントを書く他の方法のいくつかと快適に共存しますが、他の方法とはあまりうまく共存しません。複数行の制御されたステートメントが次のように記述されている場合:

if (condition)
{
  statement;
  statement;
}

そうすれば、どのステートメントが1行を制御し、どのifステートメントが複数行を制御するかが視覚的にわかります。ただし、複数行のifステートメントが次のように記述されている場合:

if (condition) {
  statement;
  statement;
}

ifその場合、必要な中括弧を追加せずに単一ステートメントの構成を拡張しようとする可能性がはるかに高くなる可能性があります。

コードベースがフォームを大幅に使用している場合は、次の行の単一ステートメントifステートメントも問題になる可能性があります

if (condition) statement;

私自身の好みは、ステートメントを独自の行に配置するifと、同様の制御ブロックを持つステートメントが多数ある場合を除いて、一般的に読みやすさが向上することです。

if (x1 > xmax) x1 = xmax;
if (x1 < xmin) x1 = xmin;
if (x2 > xmax) x2 = xmax;
if (x2 < xmin) x2 = xmin;
etc.

その場合、私は通常、そのようなifステートメントのグループの前後に空白行を付けて、他のコードから視覚的に分離します。すべてが同じインデントで始まる一連のステートメントがあるとif、何か異常があることを明確に視覚的に示すことができます。

于 2015-07-16T21:16:22.607 に答える
0

「常に中かっこを使用する」キャンプに10年間在籍した後、私は最近、中かっこをあまり使用しないように切り替えました。クリーンなコードを書く方法に関するボブおじさんの議論のいくつかに主に触発されて、中かっこなしでそれらを書く方が読みやすいと今では信じています。

if(guardClause)
      throw new SomeException(..)

ボブおじさんは、if / forステートメント内に複数行のコードを書くことは、読みやすさの匂いになる可能性があると主張しています。

例えば

if(someCondition)
{
   doTechnicalThingX();
   doTechnicalThingY();
   doTechnicalThingZ();
}

おそらく次のようにリファクタリングする必要があります

if(someCondition)
    doFunctionalThingA();

どういうわけか、ifブロック内にコードを記述しすぎているというリマインダーを受け取るので、中かっこを入れない方が役立ちます。

他の人が言っているように、コードスタイルはチームの決定だと私は信じています。

于 2021-08-12T12:10:11.350 に答える