是否使用大括号进行其他作用域

Do you use curly braces for additional scoping?

本文关键字:其他 作用域 是否      更新时间:2023-10-16

我的意思是,除了在函数、类、if、while、switch、try-catch需要时使用它之外。

直到我看到这个SO问题,我才知道它可以这样做。

在上面的链接中,Eli提到"他们用它把代码折叠在逻辑部分中,这些逻辑部分不属于通常会折叠的函数、类、循环等。"

除了上述用途外,还有什么其他用途?

使用大括号来限制变量的范围,并仅在需要时扩展范围(在"需要访问"的基础上工作),这是一个好主意吗?或者这真的很傻?

使用作用域,这样您就可以在不同的作用域中使用相同的变量名,但在同一个更大的作用域内,怎么样?还是更好的做法是重用同一个变量(如果你想使用相同的变量名)并节省释放和分配(我认为一些编译器可以对此进行优化?)?还是完全使用不同的变量名更好?

如果我正在使用我想在特定时间释放的资源,我会这样做,例如:

void myfunction()
{
  {
  // Open serial port
     SerialPort port("COM1", 9600);
     port.doTransfer(data);
  } // Serial port gets closed here.
  for(int i = 0; i < data.size(); i++)
     doProcessData(data[i]);
  etc...
}

出于几个原因,我不会为此使用大括号。

  1. 如果您的特定函数足够大,需要执行各种作用域技巧,可以将该函数分解为更小的子函数。

  2. 引入大括号来确定作用域以重用变量名只会导致代码中的混乱和麻烦。

只有我的2美分,但我在其他最佳实践材料中看到了很多这样的东西。

C++

有时,当有意义时,您需要引入一个额外的大括号级别的作用域来重用变量名:

switch (x) {
    case 0:
        int i = 0;
        foo(i);
        break;
    case 1:
        int i = 1;
        bar(i);
        break;
}

上面的代码没有编译。你需要做到:

switch (x) {
    case 0:
        {
            int i = 0;
            foo(i);
        }
        break;
    case 1:
        {
            int i = 1;
            bar(i);
        }
        break;
}

我经常使用的作用域最常见的"非标准"用法是使用作用域互斥。

void MyClass::Somefun()
{
    //do some stuff
    {
        // example imlementation that has a mutex passed into a lock object:
        scopedMutex lockObject(m_mutex); 
        // protected code here
    } // mutex is unlocked here
    // more code here
}

这有很多好处,但最重要的是,即使在受保护的代码中抛出异常,锁也会始终被清除。

正如其他人所说,最常见的用途是确保析构函数在您希望的时候运行。它还可以方便地使特定于平台的代码更加清晰:

#if defined( UNIX )
    if( some unix-specific condition )
#endif
    {
        // This code should always run on Windows but 
        // only if the above condition holds on unix
    }

为Windows构建的代码看不到if,只看到大括号。这比清楚得多

#if defined( UNIX )
    if( some unix-specific condition ) {
#endif
        // This code should always run on Windows but 
        // only if the above condition holds on unix
#if defined( UNIX )
    }
#endif

它对代码生成器来说是一个福音。假设您有一个嵌入式SQL(ESQL)编译器;它可能希望将SQL语句转换为需要本地变量的代码块。通过使用块,它可以反复使用固定的变量名,而不必使用单独的名称创建所有变量。诚然,这并不太难,但它比必要的更难。

正如其他人所说,由于功能强大的RAII(资源获取就是初始化)习惯用法/模式,这在C++中相当常见。

对于Java程序员(也许还有C#,我不知道)来说,这将是一个陌生的概念,因为基于堆的对象和GC会扼杀RAII。IMHO,能够将对象放在堆栈上是C++相对于Java的最大优势,并且使编写良好的C++代码比编写良好的Java代码干净得多。

我只在需要通过RAII释放某些东西时使用它,即使在那时,也只有在应该尽早释放它的时候使用它(例如释放锁)。

在Java中编程我经常想限制方法的范围,但我从未想过要使用标签。由于我在使用标签作为中断目标时会将其大写,因此在这些情况下,使用您建议的混合大小写标签块正是我想要的。

代码块通常太短,无法分解成一个小方法,通常是框架方法中的代码(如startup()或shutdown()),实际上最好将代码放在一个方法中。

就我个人而言,我讨厌简单的浮动/悬挂支架(尽管这是因为我们是一家严格的横幅式缩进店),我讨厌评论标记:

// yuk!
some code
{
scoped code
}
more code
// also yuk!
some code
/* do xyz */ {
    scoped code
    }
some more code
// this I like
some code
DoXyz: {
    scoped code
    }
some more code

我们考虑使用"if(true){",因为Java规范特别规定这些将在编译中进行优化(if(false)的整个内容也是如此——这是一个调试功能),但我讨厌在我尝试过的几个地方这样做

所以我认为你的想法很好,一点也不傻。我一直以为我是唯一一个想这么做的人。

是的,我使用这种技术是因为RAII。我在C中也使用了这种技术,因为它使变量更紧密地结合在一起。当然,我应该考虑更多地分解功能。

我做的一件事可能在风格上有争议,那就是把开头的大括号放在声明的行上,或者在上面加上评论。我想减少浪费的垂直空间。这是基于谷歌C++风格指南的建议。。

/// c++ code
/// references to boost::test
BOOST_TEST_CASE( curly_brace )
{
  // init
  MyClass instance_to_test( "initial", TestCase::STUFF ); {
    instance_to_test.permutate(42u);
    instance_to_test.rotate_left_face();
    instance_to_test.top_gun();
  }
  { // test check
    const uint8_t kEXP_FAP_BOOST = 240u;
    BOOST_CHECK_EQUAL( instance_to_test.get_fap_boost(), kEXP_FAP_BOOST);
  }
}

我同意agartzke的观点。如果您觉得需要对更大的逻辑代码块进行分段以提高可读性,则应该考虑重构以清理繁忙和混乱的成员。

它有它的位置,但我不认为这样做是一个好主意,即$foo可以是同一函数或其他(逻辑而非词汇)范围内的一个变量这里和另一个变量那里。尽管编译器可能完全理解这一点,但对于试图阅读代码的人来说,这似乎太可能会让生活变得困难。

我所在的公司有一个静态分析策略,可以在函数开头附近保留局部变量声明。很多时候,用法是在函数的第一行之后有很多行,所以我无法在屏幕上同时看到声明和第一个引用。我所做的"规避"策略是将声明保持在引用附近,但通过使用大括号来提供额外的作用域。不过,它增加了缩进,有些人可能会认为这会使代码变得更丑陋。