我在读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++;
    }
}

就变成:

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++中运行过三元运算符,我不知道这是否有效,但它确实存在。

简而言之:

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

其他回答

我对这位讲师的能力表示怀疑。考虑到他 点:

OK Would anyone really write (or want to read) (b*b) - ((4*a)*c)? Some precedences are obvious (or should be), and the extra parentheses just add to confusion. (On the other hand, you _should_ use the parentheses in less obvious cases, even if you know that they're not needed.) Sort of. There are two wide spread conventions for formatting conditionals and loops: if ( cond ) { code; } and: if ( cond ) { code; } In the first, I'd agree with him. The opening { is not that visible, so it's best to assume it's always there. In the second, however, I (and most of the people I've worked with) have no problem with omitting the braces for a single statement. (Provided, of course, that the indentation is systematic and that you use this style consistently. (And a lot of very good programmers, writing very readable code, omit the braces even when formatting the first way.) NO. Things like if ( NULL == ptr ) are ugly enough to hinder readability. Write the comparisons intuitively. (Which in many cases results in the constant on the right.) His 4 is bad advice; anything which makes the code unnatural makes it less readable. NO. Anything but int is reserved for special cases. To experienced C and C++ programmers, the use of unsigned signals bit operators. C++ doesn't have a real cardinal type (or any other effective subrange type); unsigned doesn't work for numeric values, because of the promotion rules. Numerical values on which no arithmetic operations would make sense, like serial numbers, could presumably be unsigned. I'd argue against it, however, because it sends the wrong message: bitwise operations don't make sense either. The basic rule is that integral types are int, _unless_ there is a significant reason for using another type. NO. Doing this systematically is misleading, and doesn't actually protect against anything. In strict OO code, delete this; is often the most frequent case (and you can't set this to NULL), and otherwise, most delete are in destructors, so you can't access the pointer later anyway. And setting it to NULL doesn't do anything about any other pointers floating around. Setting the pointer systematically to NULL gives a false sense of security, and doesn't really buy you anything.

查看任何典型参考文献中的代码。Stroustrup违反 除了第一条,你给出的每一条规则。

我建议你换个讲师。一个真正知道什么的人 他说的是。

它更直观,更容易理解。它使意图明确。

它还确保当新用户在添加新代码语句时不知不觉地漏掉{,}时,代码不会中断。

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

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

所有其他答案都捍卫了讲师的规则3。

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

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

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

是的,这可以通过在前一行上加上开大括号在一定程度上得到缓解。所以:如果你坚持使用大括号,至少要把左大括号放在前一行。

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


在最初写答案的时间里,我基本上接受了流行的代码风格,使用大括号,除非我能把整个语句放在前一行。我仍然认为不使用冗余大括号通常更具可读性,而且我仍然从未遇到过由此引起的错误。

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

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

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