今天给同事复查代码时,我发现了一件奇怪的事情。他把他的新代码用大括号括起来,就像这样:
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
另一个使用的例子是与ui相关的类,尤其是Qt。
例如,你有一些复杂的UI和很多小部件,每个小部件都有自己的间距、布局等。不是命名为space1, space2, spaceBetween, layout1,…对于只存在于2 - 3行代码中的变量,可以避免使用非描述性的名称。
好吧,有些人可能会说你应该把它分成方法,但是创建40个不可重用的方法看起来不太好——所以我决定在它们之前添加大括号和注释,所以它看起来像逻辑块。
例子:
// Start video button
{
<Here goes the code >
}
// Stop video button
{
<...>
}
// Status label
{
<...>
}
我不能说这是最佳实践,但对于遗留代码来说是一个很好的实践。
当很多人把他们自己的组件添加到UI中,一些方法变得非常庞大时,就会出现这些问题,但在类中创建40个一次性使用的方法已经搞砸了,这是不现实的。
这与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来说很重要。
正如其他人所指出的那样,一个新的块引入了一个新的作用域,使人们能够使用自己的变量编写一些代码,这些变量不会破坏周围代码的名称空间,并且只使用必要的资源。
然而,这样做还有一个很好的理由。
它只是将实现特定(子)目的的代码块分离出来。很少有一个语句能达到我想要的计算效果;通常需要好几个人。将它们放在一个块中(带有注释)可以让我告诉读者(通常是我自己在以后的日期):
这个块有一个连贯的概念目的
以下是所需的所有代码
这里有一个关于大块的评论。
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 ;
}
你可能会说我应该写一个函数来完成所有这些。如果我只做一次,写一个函数只是增加了额外的语法和参数;这似乎没什么意义。把它看成是一个无参数的匿名函数。
如果你幸运的话,你的编辑器将有一个折叠/展开功能,甚至可以让你隐藏块。
我一直都这么做。知道我需要检查的代码的界限是一件非常愉快的事情,甚至更好的是知道如果那块代码不是我想要的,我不需要查看任何一行。