【问题标题】:Do you use curly braces for additional scoping? [closed]您是否使用花括号进行额外的范围界定? [关闭]
【发布时间】:2010-09-19 22:12:34
【问题描述】:

我的意思是在函数、类、if、while、switch、try-catch 等需要时使用它。

我不知道它可以像this until I saw this SO question那样完成。

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

除了上面提到的还有什么其他用途?

使用花括号来限制变量的范围并仅在需要时扩展范围是个好主意(在“需要访问”的基础上工作)?还是真的很傻?

如何使用范围,以便您可以在不同范围但在相同更大范围内使用相同的变量名?还是重用相同的变量(如果您想使用相同的变量名)并节省释放和分配(我认为某些编译器可以对此进行优化?)是一种更好的做法?还是完全使用不同的变量名更好?

【问题讨论】:

  • 请不要重新标记您的问题在 2 年后包含 c#,因为它会极大地影响此页面上的答案和 cmets

标签: curly-braces scope c++ java


【解决方案1】:

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

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...
}

【讨论】:

  • 是的,RAII 是使用“匿名”范围而不是创建新函数的最佳理由,因为 RAII 变量的绑定范围通常非常小。
  • SerialPort 实现 IDisposable。您应该使用using 块来确保资源被释放。
  • @JDB 问题当时被标记为c+++ 而不是c# so IDisposable` 不适用。否则我完全同意你的看法
  • @MickyD 很公平,但在我为它辩护时,它也被标记为 C#。
  • @AdamHouldsworth 不用担心。谁动了我的奶酪? :)
【解决方案2】:

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

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

  2. 引入大括号来重复使用变量名只会导致代码混乱和麻烦。

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

【讨论】:

  • 这也是我的观点——如果我需要隐藏某些东西,我只需要使用#region#endregion
  • 我同意,函数应该用于作用域,如果你使用匿名作用域或#region 等技巧来使你的函数更容易理解或编写,那么你绝对应该将它拆分为其他函数。
【解决方案3】:

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;
}

【讨论】:

  • 您应该修复示例以在两种情况下使用相同的变量“i”。如果你使用“i”和“j”,代码编译得很好。
  • @Paulo 它不应该编译,你应该在跳过 i 的初始化时得到一个错误。请参阅标准的第 6.7#3 节(包括注释 2)。
  • 对不起,我不明白你跳过 i 的初始化是什么意思,你有第 6.7#3 节的链接吗?它在我的代码片段编译器上编译得很好。
  • @Paulo csci.csusb.edu/dick/c++std/cd2/stmt.html#stmt.dcl 可以转移到块中,但不能通过初始化绕过声明。除非变量具有 POD 类型 (_basic.types_) 并且在没有初始化程序 ( _dcl.init_)。还有2)从switch语句的条件到case标签的转移在这方面被认为是一个跳转。
  • 哦,你说的是C++!这段代码在 C# 上运行良好 :)
【解决方案4】:

我经常使用的最常见的“非标准”作用域使用是使用作用域互斥体。

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
}

这有很多好处,但最重要的是锁总是会被清理掉,即使在受保护的代码中抛出了异常。

【讨论】:

    【解决方案5】:

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

    #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
    

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        正如其他人所说,由于功能强大的 RAII(资源获取即初始化)惯用语/模式,这在 C++ 中相当普遍。

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

        【讨论】:

        • 警告:咆哮警报! :)
        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

          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) 的全部内容也将被优化 - 这是一个调试功能),但我讨厌在我试过的几个地方。

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

          【讨论】:

          • 好主意!这是我 8 年后想做完全相同的事情,谢谢
          【解决方案10】:

          是的,我使用这种技术是因为 RAII。我也在普通的 C 中使用这种技术,因为它使变量更接近。当然,我应该考虑更多地分解功能。

          我做的一件可能在风格上引起争议的事情是将左花括号放在声明的行上或在其上放置评论。 I want to decrease the amount of wasted vertical space. This is based on the Google C++ Style Guide recommendation..

          /// 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);
            }
          }
          

          【讨论】:

            【解决方案11】:

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

            【讨论】:

              【解决方案12】:

              它有它的位置,但我不认为这样做是为了让 $foo 在同一个函数中可以是一个变量 here 和一个不同的变量 there或其他(逻辑,而不是词法)范围是一个好主意。尽管编译器可能完全理解这一点,但对于试图阅读代码的人类来说,这似乎太难了。

              【讨论】:

                【解决方案13】:

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

                【讨论】:

                  猜你喜欢
                  • 2012-01-18
                  • 1970-01-01
                  • 2013-12-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-10-07
                  相关资源
                  最近更新 更多