揭示在我的C ++代码中创建临时值的最快方法是什么?
答案并非总能从标准中轻易推断,编译器优化可以进一步消除临时性。
我已经用 godbolt.org 进行了实验,并且非常棒。不幸的是,当谈到临时工时,它经常隐藏在装配工木头后面的树木。此外,积极的编译器优化选项使汇编程序完全不可读。
有任何其他方法可以实现这一目标吗?
答案 0 :(得分:4)
“编译器优化可以进一步消除临时性。”
您似乎对C ++语义略有误解。 C ++标准讨论了临时定义程序的形式语义。这是一种描述大量可能执行的简洁方法。
实际编译器不需要像这样表现。通常,他们不会。真正的编译器知道寄存器,真正的编译器并不假装POD有(微不足道的)构造函数和析构函数。这在优化之前已经发生。我不知道任何编译器会在调试模式下生成琐碎的ctors。
现在标准描述的一些语义只能通过非常接近的近似来实现。当析构函数具有明显的副作用时(想想std::cout
),这些类型的临时性不能完全消除。但是真正的编译器可能会在不分配任何存储空间的情况下实现可见的副作用。临时存在或不存在的概念是二元视图,实际上存在中间形式。
答案 1 :(得分:2)
由于“as-if”规则,尝试查看编译过程以查看临时创建位置可能不可靠。
但是,在记住标准的以下段落的同时阅读代码(和编码)可能有助于找到临时创建的地方,[class.temporary]/2
临时对象的具体化通常会尽可能地延迟,以避免产生不必要的临时对象。 [注意:临时对象已实现:
绑定对prvalue的引用时的
([dcl.init.ref],[expr.type.conv],[expr.dynamic.cast],[expr.static.cast],[expr.const] .cast],[expr.cast]),
在类prvalue([expr.ref],[expr.mptr.oper])上执行成员访问时,
执行数组到指针转换或在数组prvalue上进行下标时,
从braced-init-list([dcl.init.list])初始化std :: initializer_list类型的对象时,
对于某些未评估的操作数([expr.typeid],[expr.sizeof])和
当prvalue显示为废弃值表达式时。
在来自C ++ 17标准的这一段中,术语 prvalue 有一个新定义[basic.lval]/1:
prvalue是一个表达式,其求值初始化一个对象或一个位域,或者计算一个运算符的操作数的值,由它出现的上下文指定。
在最后一个标准(前C ++ 20)中,段落[basic.lval]已被移动到 Expressions [expr],因此我们所知道的值类别正在发展成为表达类别。