关于c ++:对于单行if或循环使用大括号(即{})的目的是什么?

What's the purpose of using braces (i.e. {}) for a single-line if or loop?

我正在读我的C++讲师的一些讲稿,他写了如下内容:

  • Use Indentation // OK
  • Never rely on operator precedence - Always use parentheses // OK
  • Always use a { } block - even for a single line // not OK, why ???
  • Const object on left side of comparison // OK
  • Use unsigned for variables that are >= 0 // nice trick
  • Set Pointer to NULL after deletion - Double delete protection // not bad
  • 第三种方法对我来说并不清楚:我放一行进去会得到什么一个{ ... }

    例如,以这个奇怪的代码为例:

    1
    2
    3
    4
    5
    6
    7
    8
    int j = 0;
    for (int i = 0 ; i < 100 ; ++i)
    {
        if (i % 2 == 0)
        {
            j++;
        }
    }

    替换为:

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

    使用第1版有什么好处?


    在增加EDOCX1[1]时,我们也尝试修改EDOCX1[0]。

    1
    2
    3
    4
    5
    int j = 0;
    for (int i = 0 ; i < 100 ; ++i)
        if (i % 2 == 0)
            j++;
            i++;

    哦不!从python来看,这看起来不错,但实际上不是,因为它相当于:

    1
    2
    3
    4
    5
    int j = 0;
    for (int i = 0 ; i < 100 ; ++i)
        if (i % 2 == 0)
            j++;
    i++;

    当然,这是一个愚蠢的错误,但即使是一个有经验的程序员也能犯。

    另一个很好的理由是在Ta.speot.is的答案中指出的。

    我能想到的第三个是嵌套的if

    1
    2
    3
    if (cond1)
       if (cond2)
          doSomething();

    现在,假设您现在想在不满足cond1的情况下使用doSomethingElse()(新功能)。所以:

    1
    2
    3
    4
    5
    if (cond1)
       if (cond2)
          doSomething();
    else
       doSomethingElse();

    这显然是错误的,因为else与内部if有关。

    编辑:由于这引起了一些注意,我会澄清我的观点。我要回答的问题是:

    What's the benefit of using the 1st version?

    我已经描述过了。有一些好处。但是,在我看来,"总是"的规则并不总是适用。所以我并不完全支持

    Always use a { } block - even for a single line // not OK, why ???

    我不是说总是用一个{}块。如果这是一个足够简单的条件和行为,请不要这样做。如果您怀疑有人稍后可能进来,请更改代码以添加功能。


    如果不使用{},很容易意外地用注释更改控制流。例如:

    1
    2
    3
    4
    5
    6
    if (condition)
      do_something();
    else
      do_something_else();

    must_always_do_this();

    如果您用一行注释来注释do_something_else(),您将得到以下结果:

    1
    2
    3
    4
    5
    6
    if (condition)
      do_something();
    else
      //do_something_else();

    must_always_do_this();

    它编译,但并不总是调用must_always_do_this()

    我们的代码库中存在这个问题,在发布之前,有人很快就进入其中禁用了一些功能。幸运的是,我们在代码审查中发现了它。


    我对讲师的能力有疑问。考虑到他的要点:

  • 好啊
  • 有人真的会写(或想读)(b*b) - ((4*a)*c)吗?一些先例是显而易见的(或者应该是),还有一些附加的括号只是增加了混乱。(另一方面,你应该使用在不太明显的情况下插入括号,即使你知道它们不是需要。)
  • 某种程度上。格式化有两种广泛分布的约定条件和循环:
    1
    2
    3
    if ( cond ) {
        code;
    }

    还有:

    1
    2
    3
    4
    if ( cond )
    {
        code;
    }

    首先,我同意他的观点。开口EDOCX1[1]不可见,所以最好假设它一直在那里。然而,在第二个阶段,我(和我共事过的大多数人)不介意忽略单个语句的大括号。(当然,前提是缩进是系统化的,并且您始终使用这种样式。(还有很多非常好的程序员,写了非常可读的代码,省略了即使格式化第一种方式,大括号也是如此。)

  • 不,像if ( NULL == ptr )这样的东西丑陋得足以阻碍可读性。直观地写下比较。(在很多情况下结果是右边的常量。)他的4是坏建议;任何东西这使得代码变得不自然,使其可读性变差。
  • 不,除了int以外的任何东西都是为特殊情况保留的。到有经验的C和C++程序员,使用EDCOX1,4位信号位运算符。C++没有真正的基数类型(或其他任何类型)。有效子范围类型);unsigned不适用于数值,因为晋升规则。数值,不算术运算是有意义的,就像序列号一样,可以大概是unsigned。但是,我反对它,因为它发送错误的消息:按位操作也没有意义。基本规则是积分类型为int,除非使用其他类型的重要原因。
  • 不,系统地这样做是误导,实际上防患于未然。在严格的OO代码中,delete this;通常是最常见的情况(不能将this设置为NULL),以及否则,大多数delete都在析构函数中,因此您无法访问无论如何,稍后指针。把它设置到EDOCX1[10]没有任何作用。任何其他的指针。设置指针系统地对NULL给出了错误的安全感,而不是真的给你买任何东西。
  • 查看任何典型引用中的代码。stroustrup违反例如,除了第一条规则之外,你给出的每一条规则。

    我建议你再找一个讲师。真正知道什么的人他在说。


    所有其他答案都支持你的讲师规则3。

    让我说我同意你的观点:这条规则是多余的,我不建议这么做。如果你总是加上花括号,理论上它可以防止错误。另一方面,我在现实生活中从未遇到过这样的问题:与其他答案所暗示的相反,我从来没有忘记在必要时添加花括号。如果使用适当的缩进,那么很明显需要在多个语句缩进一次后添加大括号。

    "组件10"的答案实际上突出了唯一可能导致错误的情况。但是另一方面,通过正则表达式替换代码无论如何都需要非常小心。

    现在让我们看看奖牌的另一面:总是使用花括号有什么缺点吗?其他答案只是忽略了这一点。但是有一个缺点:它占用了很多垂直的屏幕空间,这反过来会使代码不可读,因为这意味着你必须滚动更多的内容。

    在开始时考虑一个带有很多保护子句的函数(是的,下面是坏的C++代码,但在其他语言中,这将是一个非常常见的情况):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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);
    }

    这是一个可怕的代码,我强烈认为下面的代码可读性要高得多:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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);
    }

    同样,短嵌套循环也得益于省略大括号:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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;
    }

    比较:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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;
    }

    第一个代码简洁;第二个代码臃肿。

    是的,这在某种程度上可以通过在前一行放置开口支撑来减轻。但这仍然比没有任何花括号的代码可读性差。

    简而言之:不要编写占用屏幕空间的不必要代码。


    我正在研究的代码库中散布着一些对大括号有着病态厌恶的人编写的代码,对于后来出现的人来说,它确实可以对可维护性产生影响。

    我遇到的最常见的问题例子是:

    1
    2
    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;

    因此,当我提出并希望添加一个then语句时,如果我不小心的话,我可以很容易地得到这个结果:

    1
    2
    3
    4
    5
    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秒钟的时间,并且至少可以节省几分钟的调试时间,那么为什么不使用减少歧义选项呢?在我看来,这似乎是一种错误的经济。


    我的2C:

    Use Indentation

    明显地

    Never rely on operator precedence - Always use parentheses

    我不会用"从不"和"总是"这两个词,但总的来说,我认为这条规则是有用的。在某些语言(lisp、smalltalk)中,这不是问题。

    Always use a { } block - even for a single line

    我从来没有这样做过,也从来没有遇到过一个问题,但我知道这对学生有什么好处,尤其是如果他们以前学过Python。

    Const object on left side of comparison

    尤达情况?不,请。它损害可读性。编译代码时只需使用最大警告级别。

    Use unsigned for variables that are >= 0

    好啊。有趣的是,我听说斯特劳斯特鲁普不同意。

    Set Pointer to NULL after deletion - Double delete protection

    糟糕的建议!永远不要有指向已删除或不存在对象的指针。


    它更直观,更容易理解。它清楚地表明了意图。

    它确保了在添加新的代码语句时,当新用户可能无意中错过{}时,代码不会中断。


    为了增加上面非常明智的建议,我在重构一些关键代码时遇到的一个例子是:我修改了一个非常大的代码库,以便从一个API切换到另一个API。第一个API调用如下设置公司ID:

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

    而替换需要两个电话:

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

    我开始使用非常成功的正则表达式来更改它。我们还通过Astyle传递了代码,这使代码更加可读。然后,在审查过程的一部分过程中,我发现在某些有条件的情况下,它正在改变这一点:

    1
    2
    if ( condition )
       setCompIds( compId, compSubId );

    对此:

    1
    2
    3
    if ( condition )
       setCompId( compId );
    setCompSubId( compSubId );

    这显然不是所要求的。我不得不回到开始的时候,再次这样做,将替换部分完全放在一个块内,然后手动修改任何看起来很愚蠢的内容(至少它不会是错误的)。

    我注意到Astyle现在有了选项--add-brackets,它允许您在没有括号的地方添加括号,如果您发现自己和我处于相同的位置,我强烈建议您这样做。


    我到处都在使用{},除了一些明显的例子。单线是其中一种情况:

    1
    2
    3
    4
    if(condition) return; // OK

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

    在返回前添加一些方法可能会伤害您。缩进表示满足条件时正在执行返回,但它将始终返回。

    C中使用语句的其他示例

    1
    2
    3
    4
    5
    using (D d = new D())  // OK
    using (C c = new C(d))
    {
        c.UseLimitedResource();
    }

    相当于

    1
    2
    3
    4
    5
    6
    7
    using (D d = new D())
    {
        using (C c = new C(d))
        {
            c.UseLimitedResource();
        }
    }


    我能想到的最相关的例子是:

    1
    2
    3
    4
    5
    if(someCondition)
       if(someOtherCondition)
          DoSomething();
    else
       DoSomethingElse();

    哪个if将与else配对?缩进意味着外部if得到else,但这并不是编译器看到它的方式;内部if得到else,而外部if没有。您必须知道(或在调试模式中看到它的行为方式)才能通过检查找出此代码可能失败的原因。你的期望。如果您了解python,就会更加困惑;在这种情况下,您知道indentation定义了代码块,所以您希望它根据indentation进行计算。然而,C并没有给出一个关于空白的快速翻转。

    现在,也就是说,我并不特别同意这个表面上的"总是用括号"规则。它使代码在垂直方向上非常嘈杂,从而降低了快速读取代码的能力。如果声明是:

    1
    2
    if(someCondition)
       DoSomething();

    …那么应该这样写。语句"总是使用括号"听起来像"总是用括号包围数学运算"。这将把非常简单的声明a * b + c / d转变成((a * b) + (c / d)),引入缺少一个紧密的paren(许多编码者的祸根)的可能性,为什么呢?操作顺序是众所周知的,并且执行得很好,因此括号是多余的。您只需使用括号来执行与通常应用的不同的操作顺序:例如a * (b+c) / d。块大括号是类似的;使用它们来定义在与默认值不同的情况下要做什么,并且不是"明显"(主观的,但通常是相当普通的意义)。


    仔细看答案,没有人明确说明我习惯的那种做法,讲你的代码的故事:

    1
    2
    3
    4
    5
    6
    7
    8
    int j = 0;
    for (int i = 0 ; i < 100 ; ++i)
    {
        if (i % 2 == 0)
        {
            j++;
        }
    }

    变成:

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

    j++放在与if应该向任何其他人发出的信号相同的行上,"我只希望这个块增加j"。当然,这只有在行尽可能简单的情况下才有意义,因为正如Peri提到的,在这里放置一个断点不会非常有用。

    事实上,我刚刚浏览了一段Twitter风暴API,它在爪哇有这样的代码,这里是这个幻灯片第43页的执行代码的Relabnter片段。

    1
    2
    3
    4
    5
    ...
    Integer Count = counts.get(word);
    if (Count=null) count=0;
    count++
    ...

    for循环块中有两件事,所以我不会内联该代码。我从不:

    1
    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++放在:的一边)。NB我以前没有在C++中运行三元运算符,我不知道它是否有效,但是它确实存在。

    简而言之:

    想象一下你的读者(即代码维护者)如何解释你的故事(代码)。尽可能清楚地告诉他们。如果你知道初学的编码员/学生在维护这一点,可能会尽可能多地离开{},这样他们就不会感到困惑。


    因为当您有两个没有{}的语句时,很容易遗漏一个问题。假设代码看起来像这样。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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总是失败,毕竟在hash_update功能中一切看起来都很好)。

    但是,这并不意味着我要在所有地方添加{}(在我看来,看到{})是令人讨厌的)。虽然这会引起问题,但我自己的项目从来没有这样做过,因为我的个人编码风格禁止没有{}的条件,当它们不在同一行时(是的,我同意我的编码风格是非常规的,但我喜欢它,并且我在为其他项目贡献时使用项目的代码风格)。这使得下面的代码很好。

    1
    if (something) goto fail;

    但不是下面的那个。

    1
    2
    if (something)
        goto fail;


    有一种方法可以帮助防止上面描述的错误,那就是在不使用大括号的情况下,内联希望发生的事情。当您试图修改代码时,很难不注意到错误。

    1
    2
    3
    4
    5
    6
    if (condition) doSomething();
    else doSomethingElse();

    if (condition) doSomething();
        doSomething2(); // Looks pretty obviously wrong
    else // doSomethingElse(); also looks pretty obviously wrong


    警告6:删除一个空指针比较安全,因为这是一个禁止操作的操作。因此,如果您意外地通过该路径两次,您不会导致内存损坏,而是释放可用的或已分配给其他对象的内存。

    这是静态文件作用域对象和单例对象的主要问题,它们的生命周期不太清楚,并且已知在销毁它们后会重新创建。

    在大多数情况下,您可以使用auto-ptrs来避免这种需要。


    通过清晰地定义循环和条件块的范围,它可以使代码更具可读性。它还可以让你避免意外的错误。


    我喜欢卢西恩接受的答案,事实上,我学到了很难的方法,他是对的,所以我总是使用大括号,即使是对于单行块。然而,就我个人而言,我在编写过滤器时做了一个例外,正如您在示例中所做的那样。这是:

    1
    2
    3
    4
    5
    6
    7
    8
    int j = 0;
    for (int i = 0 ; i < 100 ; ++i)
    {
        if (i % 2 == 0)
        {
            j++;
        }
    }

    在我看来杂乱无章。它将for循环和if语句分隔成单独的操作,当您真正的意图是一个操作时:计算可被2整除的所有整数。在一种更具表达力的语言中,这可以写成如下内容:

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

    在缺少闭包的语言中,过滤器不能用单个语句来表示,但必须是一个for循环,后跟一个if语句。然而,它仍然是程序员心中的一个动作,我相信这应该反映在代码中,就像这样:

    1
    2
    3
    4
    5
    6
    int j = 0;
    for (int i = 0 ; i < 100 ; ++i)
      if (i % 2 == 0)
    {
        j++;
    }


    另一个添加大括号的示例。有一次我在搜索一个bug并发现了这样的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void SomeSimpleEventHandler()
    {
        SomeStatementAtTheBeginningNumber1;
        if (conditionX) SomeRegularStatement;
        SomeStatementAtTheBeginningNumber2;
        SomeStatementAtTheBeginningNumber3;
        if (!SomeConditionIsMet()) return;
        OtherwiseSomeAdditionalStatement1;
        OtherwiseSomeAdditionalStatement2;
        OtherwiseSomeAdditionalStatement3;
    }

    如果一行一行地读取方法,您会注意到方法中存在一个条件,如果该条件不为真,则返回该条件。但实际上,它看起来像100个其他简单的事件处理程序,它们根据某些条件设置了一些变量。有一天,快速编码器进来,在方法的末尾添加了额外的变量设置语句:

    1
    2
    3
    4
    5
    {
        ...
        OtherwiseSomeAdditionalStatement3;
        SetAnotherVariableUnconditionnaly;
    }

    结果,当someConditionIsMet()执行setAnotherVariable无条件分析时,但fast guy没有注意到它,因为所有行的大小几乎都相似,即使返回条件是垂直缩进的,也不那么明显。

    如果条件返回的格式如下:

    1
    2
    3
    4
    if (!SomeConditionIsMet())
    {
        return;
    }

    它是非常明显的,快速编码器会发现它一目了然。


    如果你是一个编译器,它不会有任何区别。两者都是一样的。

    但是对于程序员来说,第一个更清晰,更容易阅读,更不容易出错。


    我认为第一个是清楚的,然后第二个。它给人一种关闭指令的感觉,当代码变得复杂时,即使是endifbegin...end,代码很少也很好。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //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++;


    有许多可能的方法来编写控制语句;它们的某些组合可能共存,但不会损害易读性,但其他组合会造成麻烦。风格

    1
    2
    if (condition)
      statement;

    将与其他一些编写控制语句的方法舒适地共存,但与其他方法不太好。如果多行控制语句写为:

    1
    2
    3
    4
    5
    if (condition)
    {
      statement;
      statement;
    }

    那么,从视觉上看,哪些if语句控制一条线,哪些语句控制多条线是显而易见的。但是,如果多行if语句写为:

    1
    2
    3
    4
    if (condition) {
      statement;
      statement;
    }

    那么,有人试图扩展单个语句if构造而不添加必要的大括号的可能性可能要高得多。

    如果代码库大量使用表单,则下一行的单个语句if语句也可能存在问题。

    1
    if (condition) statement;

    我自己的偏好是,将语句放在自己的行上通常可以提高易读性,除非有许多具有类似控制块的if语句,例如。

    1
    2
    3
    4
    5
    if (x1 > xmax) x1 = xmax;
    if (x1 < xmin) x1 = xmin;
    if (x2 > xmax) x2 = xmax;
    if (x2 < xmin) x2 = xmin;
    etc.

    在这种情况下,我通常会在这些if语句组前面和后面加一个空行,以便在视觉上将它们与其他代码分开。在同一个缩进中,所有的语句都以if开头,这将提供一个清晰的视觉指示,表明有一些异常。


    完成后,最好将指针设置为空。

    下面是一个例子,为什么:

    A级执行以下操作:

  • 分配内存块
  • 稍后,它会删除这个内存块,但不会将指针设置为空。
  • B级执行以下操作

  • 分配内存(在本例中,它碰巧被赋予了与被类A删除的内存块相同的内存块。)
  • 此时,类A和类B都有指向同一内存块的指针,就类A而言,该内存块不存在,因为它已经完成了。

    考虑以下问题:

    如果在类A中有一个逻辑错误导致它写入到现在属于类B的内存中,该怎么办?

    在这个特定的例子中,您不会得到一个错误的访问异常错误,因为内存地址是合法的,而所有的情况下,类A现在有效地破坏了类B数据。

    如果B类遇到意外的值,它最终可能会崩溃,并且当它崩溃时,很有可能,当问题出现在A类中时,您将花费相当长的时间在B类中寻找这个bug。

    如果将已删除的内存指针设置为空,则只要类A中的任何逻辑错误尝试写入空指针,就会出现异常错误。

    如果您担心指针第二次为空时出现双删除逻辑错误,请为此添加断言。

    另外:如果你要投反对票,请解释一下。


    我不得不承认,不一定总是用{}来表示单线,但这是一种很好的做法。

      百万千克1

      假设您编写的代码没有括号,如下所示:

      对于(int i=0;i<100;+i)对于(int j=0;j<100;++j)给药方法;

      百万千克1

    过了一段时间,你想要添加j循环一些其他的东西,你只需要通过对齐来完成,然后忘记添加括号。

      百万千克1

      内存释放更快。假设您有很大的范围并在内部创建大型数组(没有new),所以它们在堆栈中。这些数组将在您离开作用域后从内存中删除。但有可能你在一个地方使用这个数组,它将在堆栈中一段时间,并且是某种垃圾。由于堆栈的大小有限且非常小,因此可能会超过堆栈大小。因此,在某些情况下,最好编写{}来防止这种情况发生。注:这不是针对单线,而是针对这种情况:

      如果(…){//有些东西…//我们没有if、while等。//其他东西}//更多的东西}

      百万千克1百万千克1

      第三种使用方法与第二种类似。它不只是使堆栈更干净,而是打开一些函数。如果在长函数中使用mutex,通常最好在访问数据之前以及完成读/写之后锁定和解锁。注意,如果您有自己的classstructconstructordestructor来锁定内存,则使用这种方法。

      百万千克1百万千克1

      更重要的是:

      如果(…)如果(…)somestufacture();其他的someotherstufacture();//转到第二个if,但alligment显示它是在第一个…

      百万千克1

    总的来说,我不能说,什么是最好的方法总是使用{}为一个单一的线路,但这样做并不坏。

    重要的是,如果您为一行编写编译代码括号,那么编辑什么都不做,但是如果您的代码被解释得非常慢,那么代码就非常慢。非常轻微。


    总是有大括号是非常简单和强大的规则。但是,代码可能看起来当有很多大括号的时候就不好看了。如果规则允许省略大括号,那么应该有更详细的样式规则和更复杂的工具。否则,很容易导致代码混乱和混乱(不优雅)。因此,将单个样式规则与所使用的样式指南和工具的其余部分分开来看可能是徒劳的。我只会介绍一些关于规则3的重要细节,这些细节在其他答案中都没有提到。

    第一个有趣的细节是,该规则的大多数支持者都同意在else案件中违反该规则。换言之,他们不要求审查此类代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // pedantic rule #3
    if ( command == Eat )
    {
        eat();
    }
    else
    {
        if ( command == Sleep )
        {
            sleep();
        }
        else
        {
            if ( command == Drink )
            {
                drink();
            }
            else
            {
                complain_about_unknown_command();
            }
        }
    }

    相反,如果他们看到了,他们甚至可能建议这样写:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 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();
    }

    这在技术上违反了这条规则,因为在elseif之间没有花括号。当试图用一个无意识的工具将其自动应用到代码库时,规则的这种二重性就会显现出来。实际上,为什么要争论,只是让一个工具自动应用样式。

    第二个细节(该规则的支持者也经常忘记)是,可能发生的错误绝不仅仅是因为违反了该规则。事实上,这些几乎总是涉及违反规则1(没有人争论)。同样,从自动工具的角度来看,当违反规则1时,不难制造出一个立即抱怨的工具,因此大多数错误都可以及时捕获。

    第三个细节(经常被该规则的反对者忘记)是由单个分号表示的空语句的混淆性质。大多数有经验的开发人员迟早会被唯一放错位置的分号或使用唯一分号编写的空语句弄糊涂。两个大括号而不是一个分号在视觉上更容易被发现。