在函数内使用裸括号是一个好习惯吗?

时间:2016-06-04 17:25:55

标签: c++ scope

从技术上讲,在C ++中我们可以使用花括号来声明一个新范围。例如,在此函数中,交换两个数字

void swap_int(int& first, int& second)
{
   int temp = first;
   first = second;
   second = temp;
}

我们也可以在自己的块中声明temp

void swap_int(int& first, int& second)
{
   // Do stuf...
   {
      int temp = first;
      first = second;
      second = temp;
   }
   // Do other stuff...
}

这显然具有以下优点:temp在不再需要时直接删除。

然而,在我写的代码中,我从不使用它。此外,在第三方库的代码中,我几乎从未见过它。

为什么不公开使用?它是否会带来任何性能提升,还是仅仅意味着额外的打字工作?

2 个答案:

答案 0 :(得分:2)

我没有看到任何错误 per-se 裸括号。他们是语言的一部分,并且定义得很好。从历史上看,我发现它们有用的一个地方是使用状态代码而不是异常的代码,同时保持const良好性:

const StatusCode statusCode = DoThing();
if (statusCode == STATUS_SUCCESS) {
    Foo();
else
    Bar();

const StatusCode statusCode2 = DoAnotherThing();  // Eww variable name.
...

替代方案是:

{
    const StatusCode statusCode = DoThing();
    if (statusCode == STATUS_SUCCESS) {
        Foo();
    else
        Bar();
}

{
    // Same variable name, used for same purpose, easy to
    // find/replace, and has const guarantees. Great success.
    const StatusCode statusCode = DoAnotherThing();
    ...
}

这同样适用于诸如使用RAII的线程锁定器之类的对象(互斥对象,信号量等),或者通常任何类型的资源,您可能希望具有极短的生命周期(例如文件句柄)。

就我个人而言,我认为其罕见的原因在于它可以指示代码气味(尽管并非总是如此)。如果有裸括号,则可能有机会将功能分解出来。

举个例子,如果swap_int有多个作业,那么该函数不止一件事。通过将实际交换代码提取到另一个函数中,您可以鼓励重用!例如:

template <typename T>
void swap_anything(T &first, T& second)
{
    T temp = first;
    first = second;
    second = temp;
}

// -------------------------------------------

void swap_int(int& first, int& second)
{
   // Do stuff...
   swap_anything(first, second);

   // Do other stuff...
}

答案 1 :(得分:1)

有时这是一种很好的做法(尽管我不喜欢这个术语,因为它主观和特定于语境),但与生活中的许多事物一样,把它带到极端(在频谱的任何一端) )是一个坏主意。

您会在C ++中看到有时会引入新的范围RAII很重要,就像处理thread locks时一样。有时,创建和销毁对象的精确时刻非常重要,需要加以控制。在这些情况下,引入新范围是一种非常有用且经常使用的方法。

但事实并非如此。我们(广泛的编程社区)使用的大多数对象都没有严格的生命周期需要如此谨慎管理。因此,不值得随意引入新的范围来管理生命周期不值得微观管理的物体的寿命。

如果这样做,您将降低信噪比,人们将很难确定引入哪些范围来仔细控制重要资源,哪些范围不是。这可以在重构或开发团队代码时轻松引入错误。至少,你会使编程变得更加乏味,这很糟糕,如果可以,你通常应该避免使用violent psychopath may take it out on you