今天给同事复查代码时,我发现了一件奇怪的事情。他把他的新代码用大括号括起来,就像这样:

Constructor::Constructor()
{
   // Existing code

   {
      // New code: do some new fancy stuff here
   }

   // Existing code
}

如果有结果的话,结果会是什么?这样做的原因是什么?这种习惯从何而来?

环境是嵌入式设备。有很多遗留的C代码被包裹在c++的外衣里。有很多C转向c++的开发人员。

在这部分代码中没有临界区。我只在这部分代码中看到过。没有完成主要的内存分配,只是设置了一些标志,并进行了一些操作。

用大括号括起来的代码是这样的:

{
   bool isInit;
   (void)isStillInInitMode(&isInit);
   if (isInit) {
     return isInit;
   }
}

(不要介意代码,只要坚持花括号…,)) 在花括号之后,还有更多的位处理、状态检查和基本信号。

我和他谈过,他的动机是限制变量的范围,命名冲突,以及其他一些我不能真正理解的东西。

从我的角度来看,这似乎很奇怪,我认为花括号不应该出现在我们的代码中。在所有关于为什么可以用花括号包围代码的回答中,我看到了一些很好的例子,但你不应该把代码分成方法吗?

fsdf

当前回答

其他人已经正确地讨论了范围、RAII等可能性,但既然您提到了嵌入式环境,还有一个潜在的原因:

也许开发人员不相信这个编译器的寄存器分配,或者希望通过限制作用域内自动变量的数量来显式控制堆栈帧的大小。

下面是isInit可能会在堆栈上:

{
   bool isInit;
   (void)isStillInInitMode(&isInit);
   if (isInit) {
     return isInit;
   }
}

如果去掉花括号,isInit的空间可能会在堆栈框架中保留,即使它可能被重用:如果有许多具有类似本地化范围的自动变量,并且堆栈大小有限,这可能是一个问题。

类似地,如果你的变量被分配给了一个寄存器,超出作用域应该会强烈提示这个寄存器现在可以重用了。您必须查看使用和不使用大括号生成的汇编程序,以确定这是否有真正的区别(并对其进行分析—或观察堆栈溢出—以查看这种差异是否真的重要)。

其他回答

在多线程编程中将作用域锁与临界区结合使用时,这非常有用。在花括号中初始化的作用域锁(通常是第一个命令)将在块的末尾超出作用域,因此其他线程将能够再次运行。

正如其他人所指出的那样,一个新的块引入了一个新的作用域,使人们能够使用自己的变量编写一些代码,这些变量不会破坏周围代码的名称空间,并且只使用必要的资源。

然而,这样做还有一个很好的理由。

它只是将实现特定(子)目的的代码块分离出来。很少有一个语句能达到我想要的计算效果;通常需要好几个人。将它们放在一个块中(带有注释)可以让我告诉读者(通常是我自己在以后的日期):

这个块有一个连贯的概念目的 以下是所需的所有代码 这里有一个关于大块的评论。

e.g.

{  // update the moving average
   i= (i+1) mod ARRAYSIZE;
   sum = sum - A[i];
   A[i] = new_value;
   sum = sum + new_value;
   average = sum / ARRAYSIZE ;  
}

你可能会说我应该写一个函数来完成所有这些。如果我只做一次,写一个函数只是增加了额外的语法和参数;这似乎没什么意义。把它看成是一个无参数的匿名函数。

如果你幸运的话,你的编辑器将有一个折叠/展开功能,甚至可以让你隐藏块。

我一直都这么做。知道我需要检查的代码的界限是一件非常愉快的事情,甚至更好的是知道如果那块代码不是我想要的,我不需要查看任何一行。

那么,为什么要使用“不必要的”大括号呢?

为了“确定范围”(如上所述) 使代码在某种程度上更具可读性(很像使用#pragma,或定义可以可视化的“sections”) 因为你可以。就这么简单。

附注:这不是糟糕的代码;这是百分百有效的。所以,这是一个(不寻常的)品味问题。

一个原因可能是在新花括号块中声明的任何变量的生命周期都限制在这个块中。我想到的另一个原因是能够在最喜欢的编辑器中使用代码折叠。

额外的大括号用于定义在大括号内声明的变量的范围。这样做是为了在变量超出作用域时调用析构函数。在析构函数中,你可以释放一个互斥锁(或任何其他资源),以便其他人可以获取它。

在我的生产代码中,我写了这样的东西:

void f()
{
   // Some code - MULTIPLE threads can execute this code at the same time

   {
       scoped_lock lock(mutex); // Critical section starts here

       // Critical section code
       // EXACTLY ONE thread can execute this code at a time

   } // The mutex is automatically released here

  // Other code  - MULTIPLE threads can execute this code at the same time
}

如您所见,通过这种方式,您可以在函数中使用scoped_lock,同时可以通过使用额外的大括号定义其作用域。这可以确保即使额外大括号外的代码可以由多个线程同时执行,但大括号内的代码一次只能由一个线程执行。