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

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

当前回答

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

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

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

其他回答

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

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

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

这与if(或while等)块相同,只是没有if。换句话说,您在没有引入控制结构的情况下引入了作用域。

这种“显式范围”通常在以下情况下有用:

避免名称冲突。 范围使用。 来控制何时调用析构函数。

示例1:

{
    auto my_variable = ... ;
    // ...
}

// ...

{
    auto my_variable = ... ;
    // ...
}

如果my_variable恰好是两个彼此隔离使用的不同变量的一个特别好的名称,那么显式作用域允许您避免为了避免名称冲突而发明一个新名称。

这也允许您避免意外地使用my_variable超出其预期范围。

示例2:

namespace N1 { class A { }; }
namespace N2 { class A { }; }

void foo() {

    {
        using namespace N1;
        A a; // N1::A.
        // ...
    }

    {
        using namespace N2;
        A a; // N2::A.
        // ...
    }

}

在实际情况下,这是非常有用的,这可能表明代码已经成熟到可以重构了,但是如果您真的需要它,它的机制是存在的。

示例3:

{
    MyRaiiClass guard1 = ...;

    // ...

    {
        MyRaiiClass guard2 = ...;
        // ...
    } // ~MyRaiiClass for guard2 called.

    // ...

} // ~MyRaiiClass for guard1 called.

当释放资源的需求没有自然地“落”到函数或控制结构的边界时,这对于RAII来说很重要。

我认为其他人已经讨论了范围,所以我将提到不必要的括号也可能在开发过程中发挥作用。例如,假设您正在对现有函数进行优化。切换优化或跟踪错误到特定的语句序列对程序员来说很简单——参见大括号前的注释:

// if (false) or if (0) 
{
   //experimental optimization  
}

这种做法在调试、嵌入式设备或个人代码等特定环境中非常有用。

另一个使用的例子是与ui相关的类,尤其是Qt。

例如,你有一些复杂的UI和很多小部件,每个小部件都有自己的间距、布局等。不是命名为space1, space2, spaceBetween, layout1,…对于只存在于2 - 3行代码中的变量,可以避免使用非描述性的名称。

好吧,有些人可能会说你应该把它分成方法,但是创建40个不可重用的方法看起来不太好——所以我决定在它们之前添加大括号和注释,所以它看起来像逻辑块。

例子:

// Start video button
{
   <Here goes the code >
}
// Stop video button
{
   <...>
}
// Status label
{
   <...>
}

我不能说这是最佳实践,但对于遗留代码来说是一个很好的实践。

当很多人把他们自己的组件添加到UI中,一些方法变得非常庞大时,就会出现这些问题,但在类中创建40个一次性使用的方法已经搞砸了,这是不现实的。

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