【问题标题】:Const-correctness for non trivial variables非平凡变量的常量正确性
【发布时间】:2019-03-12 17:02:10
【问题描述】:

(有点启发 by this answer 虽然不相关)

我一直被告知(并且一直在告知)保持const-正确性,即使对于短暂的变量也是有价值和良好的做法,例如:

const std::string a = "Hello world";

代替

std::string a = "Hello world";

这个:

  • 更清楚地表达意图。
  • 确保变量是不可变的,因此将其传递给可能会改变它的函数会使编译器对您大喊大叫。
  • 可能由于编译器优化而提高性能。

尽管自从现代 C++ 引入复制省略以来,a few clauses in the standard 允许编译器调用移动构造函数而不是复制构造函数:

在以下复制初始化上下文中,移动操作可能 用于代替复制操作:

(3.1) 如果return 语句 ([stmt.return]) 中的表达式是一个(可能带括号的)id 表达式,它用 在正文中声明的自动存储持续时间或 最里面的封闭函数的参数声明子句或 lambda 表达式,或

(3.2) 如果throw-expression ([expr.throw]) 的操作数是非易失性自动对象的名称(函数或 catch 子句除外) 参数),其范围不超出最内层的末尾 附上try-block(如果有的话),

这是否意味着在遇到这种省略适用的情况时,使用带有非默认复制/移动构造函数的 const 对象实际上会降低性能,而不是提高性能?

【问题讨论】:

  • @Acorn 当优化器还没有那么成熟时,我肯定看到编译器生成的优化程序集比没有const 时生成的优化程序集更多。 (我认为这是 C++11 之前的时间)现在可能不是这种情况,因为优化器非常善于发现数据是否被修改过,所以也许它不再存在了,它只是一个古老的遗物. (比如使用inline 来提高性能)。
  • 不确定你的意思,当然我无法证明,但这听起来像是一个代码生成错误(即优化const,而他们不应该有),一个非标准实现(相同)或错过优化(即没有同等优化两种情况)。
  • @Acorn 如果您获取非常量对象的地址并将非常量指针传递给在另一个翻译单元中定义的函数,则优化器必须假定该对象可能已被修改并正在访问后面的对象一定是通过内存的吧?如果对象是 const,那么将指向它的非 const 指针传递给另一个 TU 不会阻止优化器将变量的值缓存在寄存器中,因为它无法更改。我的推理错了吗?
  • @Acorn 这是代码生成的区别:godbolt.org/z/xMuMVB
  • 顺便说一句,const 实际上可以提高性能:extern const 足够简单的对象(如 int)带有初始化程序,因为即使没有内部链接编译器可能会利用标准规定不允许更改值的事实。

标签: c++ copy-elision


【解决方案1】:

这是否意味着使用带有非默认复制/移动构造函数的 const 对象实际上会降低性能

可能是的。返回本地对象时,常量将阻止使用引用规则允许的移动构造。但实际上可能不存在性能损失,因为无论变量是否为 const,NRVO 仍可能忽略整个复制/移动。

虽然不能保证 NRVO,也不一定总是可能 - 或者根本没有启用(调试版本),因此在按值返回局部变量时使用非 const 可能是值得的。

【讨论】:

    猜你喜欢
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-24
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    相关资源
    最近更新 更多