【问题标题】:Pro/con: Initializing a variable in a conditional statement优缺点:在条件语句中初始化变量
【发布时间】:2010-09-13 06:53:23
【问题描述】:

在 C++ 中,您可以在 if 语句中初始化变量,如下所示:

if (CThing* pThing = GetThing())
{
}

为什么人们会认为这种风格不好或好?有什么好处和坏处?

我个人喜欢这种风格,因为它限制了 pThing 变量的范围,所以当它为 NULL 时永远不会被意外使用。但是,我不喜欢你不能这样做:

if (CThing* pThing = GetThing() && pThing->IsReallySomeThing())
{
}

如果有办法使上述工作,请张贴。但如果那是不可能的,我还是想知道为什么。

Question borrowed from here, similar topic but PHP.

【问题讨论】:

    标签: c++ coding-style if-statement


    【解决方案1】:

    这个应该在 C++ 中不起作用因为即使它支持short circuiting evaluation也许不要尝试以下操作:

    if ((CThing* pThing = GetThing()) && (pThing->IsReallySomeThing()))
    {
    }
    

    错误..见Wesley Tarle's answer

    【讨论】:

    • 我会尝试...我记得我尝试了各种括号放置,但没有一个会起作用,尽管编译器错误根据括号改变了很多。
    • “短路评估”......到目前为止,我只知道这是“早出”。这个对我来说是新的。
    【解决方案2】:

    我通常不这样做的一个原因是条件测试中缺少“=”的常见错误。我使用带有错误/警告设置的 lint 来捕获这些错误/警告。然后它会对条件句中的所有作业大喊大叫。

    【讨论】:

      【解决方案3】:

      关于优势:

      始终建议您在第一次需要时定义变量,而不是之前的一行。这是为了提高代码的可读性,因为无需滚动和搜索 CThing 的定义位置即可知道它是什么。

      还将范围缩小到循环/if 块,导致变量在代码块执行后未被引用,这使其成为垃圾收集的候选者(如果语言支持此功能)。

      【讨论】:

        【解决方案4】:

        仅供参考,一些较旧的 Microsoft C++ 编译器(我认为是 Visual Studios 6 和 .NET 2003)在某些情况下并不完全遵循范围规则。

        for(int i = 0; i > 20; i++) {
             // some code
        }
        
        cout << i << endl;
        

        我应该超出范围,但那是/是有效代码。我相信它是作为一个功能被玩弄的,但在我看来,它只是不合规。不遵守标准是不好的。就像一个关于 IE 和 Firefox 的网络开发者一样。

        有 VS 的人可以检查一下是否仍然有效吗?

        【讨论】:

        • 这是一个编译器选项,“在 for 语句中强制作用域”之类的。
        • 是的,它是 /Zc:forScope-“强制符合 for 循环范围”。至少在 VS 2008 中。
        • 感谢大家检查。我猜它默认开启(打破范围)?
        【解决方案5】:

        您还可以将分配包含在一组额外的 ( ) 中以防止出现警告消息。

        【讨论】:

          【解决方案6】:

          我认为这有点危险。下面的代码更安全,并且括号仍然会以您想要的方式限制 pThing 的范围。

          我假设 GetThing() 有时会返回 NULL,这就是为什么我将那个有趣的子句放在 if() 语句中。它可以防止在 NULL 指针上调用 IsReallySomething()。

          {
              CThing *pThing = GetThing();
              if(pThing ? pThing->IsReallySomeThing() : false)
              {
              // Do whatever
              }
          }
          

          【讨论】:

          • C++ 有短路求值,因此“if (pThing && pthing->IsReallySomeThing())”已经保证如果 pThing 为 null 时不会调用 IsReallySomeThing()。
          • 同意 Derek: true/false in a ?: 总是更整洁地完成 ||/&&
          【解决方案7】:

          重要的是 C++ 中的声明不是表达式。

          bool a = (CThing* pThing = GetThing()); // not legit!!
          

          您不能在 if 语句中同时进行声明和布尔逻辑,C++ 语言规范明确允许表达式或声明。

          if(A *a = new A)
          {
              // this is legit and a is scoped here
          }
          

          我们如何知道表达式中的一个术语和另一个术语之间是否定义了a?

          if((A *a = new A) && a->test())
          {
              // was a really declared before a->test?
          }
          

          咬紧牙关,使用内部 if。范围规则很有用,您的逻辑很明确:

          if (CThing* pThing = GetThing())
          {
              if(pThing->IsReallySomeThing())
              {
              }
          }
          

          【讨论】:

          • "(A *a = new A) && a->test()" 这不是标准的 C++。 (-1)
          • 我会接受这个技术冗长的答案。关于哪个更好的讨论确实是非常主观的,我更喜欢我最初帖子中的风格,但我的 TD 不希望我使用它,所以我不想。我总是可以使用一对额外的括号来限制范围作为妥协。
          【解决方案8】:

          还请注意,如果您正在编写 C++ 代码,您希望编译器在条件语句(不是声明的一部分)中警告“=”成为错误。

          【讨论】:

            【解决方案9】:

            这是可以接受的良好编码习惯。但是,不是来自低级编码背景的人可能会不同意。

            【讨论】:

              【解决方案10】:
              if (CThing* pThing = GetThing())
              

              这是不好的风格,因为在 if 内部你没有提供布尔表达式。您提供的是CThing*

              CThing* pThing = GetThing();
              if (pThing != NULL)
              

              这种风格很好。

              【讨论】:

                【解决方案11】:

                很多东西。首先,裸指针。请务必避免使用它们。使用引用、可选、unique_ptr、shared_ptr。作为最后的手段,编写自己的类来处理指针所有权,而不是其他。

                如果您可以要求 C++11(首选 C++14 以避免 C++11 缺陷),请使用统一初始化: - 它避免了 = vs == 混淆,并且在检查参数时更加严格。

                if (CThing thing {})
                {
                }
                

                确保实现 operator bool 以获得从 CThing 到 bool 的可预测转换。但是,请记住,阅读代码的其他人不会立即看到operator bool。显式方法调用通常更具可读性和令人放心。如果您需要 C++17,请使用初始化语法。

                if (CThing thing {}; thing.is_good())
                {
                }
                

                如果 C++17 不是一个选项,请按照其他人的建议使用上面的声明。

                {
                  CThing thing {};
                  if (thing.is_good())
                  {
                  }
                }
                

                【讨论】:

                  【解决方案12】:

                  您可以在ifswitch 中包含初始化语句,因为C++17

                  您的代码现在是:

                  if (CThing* pThing = GetThing(); pThing->IsReallySomeThing())
                  {
                      // use pThing here
                  }
                  // pThing is out of scope here
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2010-12-03
                    • 2018-04-28
                    • 2017-09-21
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2010-09-07
                    • 2020-08-25
                    相关资源
                    最近更新 更多