我在读c++老师的课堂笔记,他是这样写的:

使用缩进// OK 永远不要依赖运算符优先级-总是使用括号// OK 总是使用{}块-即使是单行//不可以,为什么?? Const对象在比较的左边// OK 对>= 0的变量使用unsigned,这是个不错的技巧 删除后将指针设置为NULL -双重删除保护//不错

第三种方法我不清楚:放一行进去能得到什么 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++;

使用第一个版本的好处是什么?


当前回答

我喜欢卢钦公认的答案。事实上,我经过艰苦的学习才知道他是对的,所以我总是使用大括号,即使是单行块。然而,就我个人而言,我在编写过滤器时做了一个例外,就像您在示例中所做的那样。这样的:

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

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

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

其他回答

我正在处理的代码库被那些病态地厌恶大括号的人分散在代码中,对于后来的人来说,它确实可以对可维护性产生影响。

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

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语句时,如果我不小心,我很容易以这样的方式结束:

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秒左右的时间,并且可以为您节省至少几分钟的调试时间,为什么不选择减少歧义性呢?在我看来这是虚假的节约。

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

if (condition)
  statement;

可以与其他一些编写控制语句的方法很好地共存,但与其他方法就不那么好了。如果多行受控语句被写成:

if (condition)
{
  statement;
  statement;
}

那么,从视觉上看,哪些if语句控制单行,哪些语句控制多行就很明显了。然而,多行If语句被写成:

if (condition) {
  statement;
  statement;
}

那么,如果构造不添加必要的大括号,那么试图扩展单个语句的可能性就会高得多。

如果代码库大量使用这种形式,那么下一行的单个语句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开头的语句将提供一个清晰的视觉指示,表明有不寻常的地方。

除了一些明显的情况外,我在任何地方都使用{}。单行是其中一种情况:

if(condition) return; // OK

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

当你在返回之前添加一些方法时,它可能会伤害你。缩进表示当条件满足时执行return,但它总是返回。

c#中using语句的其他例子

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();
    }
}

纵观答案,没有人明确地说明了我习惯的那种实践,讲述你的代码的故事:

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++;
}

将j++放在与if should相同的行上,向其他任何人发出信号:“我只想让这个块永远增加j”。当然,只有在行代码尽可能简单的情况下,这样做才有意义,因为在这里设置断点,正如前面提到的,并不是很有用。

事实上,我刚刚遇到了Twitter Storm API的一部分,它在Java中有这种“类型”代码。以下是执行代码的相关片段,在本幻灯片的第43页:

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

for循环块中有两个东西,所以我不会内联那个代码。也就是说,从来没有:

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

这很糟糕,我甚至不知道它是否有效(如预期的那样);不要这样做。新行和大括号有助于区分独立但相关的代码段,就像散文中的逗号或分号一样。上面的块是一个很长的句子,里面有几个从句和一些其他的语句,从来没有中断或暂停来区分不同的部分。

如果你真的想要向其他人发送一个只有一行的任务,请使用三元操作符或?:form:

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

但这几乎是代码高尔夫,我认为这不是很好的实践(我不清楚是否应该将j++放在:的一侧)。注意,我以前没有在c++中运行过三元运算符,我不知道这是否有效,但它确实存在。

简而言之:

想象一下您的读者(即维护代码的人)如何解释您的故事(代码)。让他们尽可能清楚地知道。如果您知道新手程序员/学生正在维护这个,甚至可能留下尽可能多的{},这样他们就不会感到困惑。

让我们尝试在增加j时也修改i:

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++;

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

在ta.speot中指出了另一个很好的理由。的回答。

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

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

现在,假设您现在想在未满足cond1时执行somethingelse()(新特性)。所以:

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

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


编辑:既然这引起了一些关注,我将澄清我的观点。我想回答的问题是

使用第一个版本的好处是什么?

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

总是使用{}块-即使是单行//不可以,为什么??

我并不是说总是使用{}块。如果这是一个足够简单的条件和行为,那就不要。如果你怀疑有人可能稍后会来修改你的代码来增加功能,那就这么做。