【问题标题】:Best practice for const temporary types [closed]const 临时类型的最佳实践
【发布时间】:2019-08-16 07:42:38
【问题描述】:

假设我正在做一个涉及创建一个我不会修改的临时对象的计算:

auto tmp = val * val;
// Do some calculations with tmp...

此外,我不需要 tmp 成为左值,因为我不会获取它的地址。

在这些条件下,我应该在我的代码中使用哪个成语:

1.       auto    tmp = val * val;
2. const auto    tmp = val * val;
3. const auto &  tmp = val * val;
4.       auto && tmp = val * val;
5. const auto && tmp = val * val;

请注意,我明确放弃了auto &,因为这通常会导致 UB。但是,我知道const auto & 会延长临时生命周期,所以我把它作为一个选项留在这里。

不出所料,对于这个简单的示例,-O3 无论如何都会编译成相同的代码:https://godbolt.org/z/oXj3hd

但在一个更复杂的例子中,我想他们不会。

我的想法是选项 3 或 5 可能是最正确的,因为它们将保留对象的常量性,并且因为它们将保存临时对象。

编辑:

很多人都提到,在这个简单的示例中,甚至不需要命名 temp。那是正确的。我所追求的是当生成temp的表达式很复杂时如何做的建议,并且会在代码中重复使用。

【问题讨论】:

  • 您需要的实际计算有多复杂?如果它和val * val 一样简单,为什么不能在最终表达式中直接使用它(否则会使用tmp)?
  • 请注意,您不能移动 const 对象。
  • 你应该忘记。编译器足够聪明,可以删除所有内容。如果您确实有cpu消耗问题,请测量!但是您可以相信,每个普通编译器都不会出现临时问题!改为编写可读代码!您的示例充满了或多或少可怕的编码示例 :-) 顺便说一句:“几乎自动”将让您在未来度过一些不眠之夜。
  • 我推荐stackoverflow.com/questions/13230480/what-does-auto-tell-us,其中的答案涵盖了这组选项,但它是否真的是一个骗子是值得怀疑的(问题在于解决方案,而不是问题)。
  • 最后,请注意,这个问题的答案确实(必然)取决于使用的operator*(即在一个理智的世界中按值返回的函数)。如果你想存储例如getter 的返回值(可能返回 const&),或者在模板化设置中工作,在这种设置中你不能确定从某些计算中得到了什么,事情可能再次看起来不同。

标签: c++ c++14


【解决方案1】:
auto tmp = val * val;

当您想稍后将 tmp 转换为右值 (std::move(tmp)) 时使用此选项。

const auto tmp = val * val;

以后不需要std::move(tmp) 时使用它。明确,毫不奇怪,表彰 Scott Meyers 项目“尽可能使用 const”。

const auto &  tmp = val * val;

不要这样做。它确实延长了生命周期,但与 2. 相比,您不会从中获得任何好处,因为无论如何该对象都必须存在于某个地方。当val*val 按值返回一个对象时,您不会用 2 复制它。由于 (N)RVO(假设 operator *val 对象的行为正常),所以 const auto& tmpconst auto tmp 都将引用范围堆栈中的对象。

auto && tmp = val * val;
const auto && tmp = val * val;

不会产生任何性能优势,但会使代码阅读变得复杂。不要这样做。

【讨论】:

    【解决方案2】:

    为什么要绑定对 val * val 的引用?抛开性能不谈,我认为这是一种混淆。

    不出所料,对于这个简单的示例,-O3 无论如何都会编译成相同的代码:

    是的,这里没有什么大惊喜。所以只使用最简洁和最不做作的。 const 不是为了性能,编译器足够聪明,可以意识到在没有你帮助的情况下不会修改变量,尽管const 为你记录了常量,从而增加了可读性。因此

    const auto tmp = val * val;
    

    其他任何事情都会将简单的事情变成不必要的复杂。

    最后但并非最不重要的一点是,考虑一下您是否需要临时的,或者您是否可以简单地写val*val 代替tmp。另一方面,如果你多次使用tmp,当然值得给它起一个有意义的名字(有意义=比tmp更有意义的东西;)

    PS:请注意,const 会阻止从tmp 移动,这可能会降低性能。但是,一般来说,当担心性能时,您应该首先编写可读代码,然后才能测量性能。

    【讨论】:

    • const 有利于值语义和记录不变性,但会扼杀移动语义。真的取决于基础类型,您应该更喜欢一种还是另一种。
    • @MaxLanghof 是的,我看到了您的评论,这是一个需要考虑的问题,尽管之前从未考虑过,并且必须先阅读一些内容,然后才能“修复”答案。现在我只是添加了一个“不要过早优化”的注释
    【解决方案3】:

    除非您遇到具体的实际性能问题(在这种情况下,您需要分析和衡量程序的执行情况),否则没有必要在汇编级别询问哪个选项最好。

    但是,有一个更明确且不那么令人惊讶:

    const auto    tmp = val * val;
    

    使用它,除非你能证明它的性能较低并且它对你的程序的全局可观察行为很重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-29
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-23
      • 1970-01-01
      相关资源
      最近更新 更多