【问题标题】:When should I use temporary variables? [closed]什么时候应该使用临时变量? [关闭]
【发布时间】:2010-04-27 21:30:02
【问题描述】:

具体来说,我想知道我应该写哪一个:

{
    shared_ptr<GuiContextMenu> subMenu = items[j].subMenu.lock();
    if (subMenu)
        subMenu->setVisible(false);
}

或:

{
    if (items[j].subMenu.lock())
        items[j].subMenu.lock()->setVisible(false);
}

我不需要遵守任何风格准则。优化后,我认为这两种选择都不会影响性能。通常首选的样式是什么?为什么?

编辑:items[j].subMenu 的类型是 boost::weak_ptr。 lock() 从中创建一个 shared_ptr 。实际上,上述两个版本在临时 shared_ptr 持续多长时间方面存在模棱两可的差异,因此我将两个示例包裹在 { 大括号 } 中以解决其中的歧义。

【问题讨论】:

  • lock() 是变异方法吗?看起来可能是这样。
  • @Troubadour:这是最常见的优化之一。
  • @Xavier:假设lock() 有副作用 - 怎么会?
  • @gf:因为lock这个名字意味着有东西被锁定了,所以状态发生了变化。
  • @Xavier:除非编译器可以证明没有副作用,否则它不能合并语句(因为这会改变语义)。这是不正常的,绝对不是“常见的”(与例如整数 CSE 相比)

标签: c++ styles temporaries


【解决方案1】:

另一种方法:

if(shared_ptr<GuiContextMenu> subMenu = items[j].subMenu.lock()) {
    subMenu->setVisible(false);
}
//subMenu is no longer in scope

我假设subMenuweak_ptr,在这种情况下,您的第二种方法会创建两个临时对象,这可能是也可能不是问题。您的第一个方法将变量添加到比它需要的范围更广的范围内。就我个人而言,我尽量避免在 if 语句中进行赋值,但这是我认为它比替代方法更有用的少数情况之一。

【讨论】:

  • 我个人会避免使用不会产生 bool 类型的表达式作为布尔表达式,而是更喜欢显式测试 if( subMenu != 0 ),如果你也这样做会变得混乱(并且容易出错)交作业。此外,一些没有经验的代码维护人员可能会在以后出现并通过将“=”替换为“==”来“纠正”此代码。
  • 你并不孤单,但这并不能阻止我们其他人这样做。
  • 我赞同 Clifford 的评论。我今天在写类似的成语,并把它和一条评论配对,说“有史以来最糟糕的成语之一”。
  • @Clifford:您的更改会导致编译错误。在这种情况下,有几个事实都收敛了。变量的范围隐式地与 if 语句相关联;如果该值未通过该测试,则[通常]您无能为力。有问题的类型是布尔类型,具有适当的隐式转换。变量的范围是有意义的;您希望尽早销毁weak_ptr。在这些特定情况下,我觉得以这种方式声明变量提供了足够的有意义的信息来证明可读性的轻微损失是合理的。显然,YMMV。
  • @Dennis Zickefoose:有什么变化?什么错误信息?隐式演员正是我建议应该避免的。在其他方面;在这个例子中你可能有一个观点,但我想知道为什么原始示例与模板类型“复杂”,而实际问题似乎更笼统。在 OP 的编辑中使用额外的大括号可能会解决范围问题。
【解决方案2】:

这种特殊情况中,您确实应该使用带有临时变量的版本。原因不是性能,而是正确性 - 基本上,您不能保证两个 x.lock() 调用返回相同的值(例如,如果另一个线程在两个调用之间释放对象的最后一个强引用)。通过在临时变量中保存强引用,您可以确保它不会消失。

除此之外:

  • 编译器通常无法优化函数调用,除非它们可以证明没有副作用(这很难做到,但属性可能会有所帮助)或内联。在这种情况下,调用有副作用。

  • 使用临时文件可以生成更短、更易读、更易于维护的程序(例如,如果出现错误,您可以在一处修复)

【讨论】:

    【解决方案3】:

    我认为您对任何一种选择在优化后都没有什么不同是正确的。

    就我个人而言,如果它使代码更具可读性,我会声明一个新变量,例如在链接调用或将函数调用放入函数调用时。只要它是可维护的并且代码在没有速度差异的情况下达到相同的效果,这一切都归结为可读的代码。

    编辑:

    mmyers 买了一个很好的评论。是的,请小心拨打lock() 两次,而不是一次。根据您的实施,它们会产生不同的效果。

    【讨论】:

    • 程序员而不是编译器的代码。编译器足够聪明,可以弄清楚。总是把最易读的代码放在最前面,然后在必要时优化它
    【解决方案4】:

    选择基本上取决于您,但您应该注意的基本事项是可维护性。

    【讨论】:

      【解决方案5】:

      当返回值不是布尔值时,将其分配给中间变量通常可以简化调试。例如,如果您跳过以下内容:

      if( fn() > 0 ) ...
      

      事后你会知道,函数返回的值要么小于零,要么为零或更大。即使返回值不正确,代码似乎仍然可以工作。将它分配给可以在调试器中检查的变量将允许您确定返回值是否是预期的。

      当返回为布尔值时,实际值完全被代码流隐含,因此不那么关键;但是,在代码维护期间,您可能会发现稍后您需要该结果,因此您可能决定在任何情况下都养成习惯。

      即使返回值是布尔值,另一个需要考虑的问题是函数是否需要副作用,以及这是否会受到短路评估的影响。例如在声明中:

      if( isValid && fn() ) ...
      

      函数永远不会被调用 isValid 为 false。

      粗心的程序员(通常是经验不足的程序员承担维护任务)在维护时可能会破坏代码的情况很多,最好避免。

      【讨论】:

        【解决方案6】:

        在这个具体的例子中,我认为这取决于lock() 做了什么。功能贵吗?每次调用函数时它会返回不同的东西吗(它是否第一次返回指针而第二次返回 NULL)?是否有另一个线程可以在对lock() 的两次调用之间交错运行?

        对于此示例,您需要了解 lock() 的行为以及您的其余代码才能做出明智的决定。

        【讨论】:

          【解决方案7】:

          我大多数时候更喜欢第一个,因为它使代码更清晰易读,因此更不容易出错。例如,您忘记了第二个示例的括号:) 在这种情况下,实际上,我可能会执行您在第二个示例中所做的操作,但是如果我需要多次使用该子菜单,我会使用第一个以使代码更易于阅读。至于性能,我认为任何理智的编译器都可以对其进行优化(这可能就是您没有看到性能差异的原因)。

          另外,正如 mmyers 所指出的,这也取决于 lock() 的作用。一般来说,如果它是一个简单的 getter 方法或类似的东西,你会没事的。

          【讨论】:

            【解决方案8】:

            随你喜欢。对我来说,这取决于我会用多少;对于两行,我可能只写两次,而如果我更多地使用它,我会创建一个变量。但是,您最有可能必须维护此代码并继续查看它,因此请使用适合您的任何内容。当然,如果您所在的公司有编码指南,请遵循它。

            【讨论】:

              【解决方案9】:

              我认为首选样式是您认为使您的代码更具可读性和可维护性的任何样式。如果你是一个多人的团队,唯一的另一个考虑是每个人都采用相同的风格通常是一个好主意,同样是为了可读性和易于维护。

              【讨论】:

                【解决方案10】:

                在这种情况下,我认为您应该使用临时的。即使您知道 .lock() 的实现很便宜,那也可以改变。如果您不需要调用 lock() 两次,请不要。这里的价值在于它将您的代码与 lock() 的实现分离。这通常是一件好事。

                【讨论】:

                  猜你喜欢
                  • 2017-09-11
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-12-23
                  • 2021-07-13
                  • 1970-01-01
                  • 2021-09-07
                  • 2022-01-02
                  相关资源
                  最近更新 更多