简单的问题,但令人惊讶的是很难找到。对于语句A && B
,我知道在A
和B
的求值之间有一个序列点,并且我知道计算的顺序是从左到右的,但是当编译器能够证明B
总是错误的(甚至是显式的)时,它允许做什么?
也就是说,对于function_with_side_effects() && false
,编译器是否允许优化函数调用?
发布于 2016-06-01 09:38:06
允许编译器优化任何东西,只要它不破坏(如果是规则)。as-if规则指出,对于可观察的行为,程序的行为必须像由C++抽象机器的精确规则执行一样(基本上是正常的、未优化的代码语义)。
可观察到的行为是:
volatile
对象只要程序按照正确的顺序完成上述三件事情,就可以任意偏离其他源代码功能。
当然,在实际操作中,编译器必须保持不变的操作数要比上面的操作大得多,因为编译器必须假定其代码所看不到的任何函数都可能具有可观察的效果。
因此,在您的示例中,除非编译器能够证明function_with_side_effects
中的任何操作都不会影响可观察的行为(直接或间接地通过设置稍后测试的标志),否则它必须执行function_with_side_effects
调用,因为如果不这样做,就可能违反“如果规则”。
正如@T.C.在注释中正确指出的那样,允许编译器执行可观察行为的优化时,as-if规则有几个例外;在这些异常中最常见的是复制省略。但是,这些异常都不会在所讨论的代码中起作用。
发布于 2016-06-01 09:47:31
No.
通常,C++标准根据可观察的效果指定计算结果,并且只要您的代码是以符合标准的方式编写的(避免未定义的行为、未指定的行为和实现定义的行为),那么兼容的编译器必须按照指定的顺序生成可观察的效果。
标准中只有两个注意事项:返回值时的复制省略允许编译器省略对复制构造器或移动构造器的调用,而不考虑它们(潜在的)可观察的效果。
否则,编译器只允许优化不可观察的行为,例如,使用较少的CPU寄存器或不将值写入您以后从未读取过的内存位置。
注意:在C++中,可以观察到对象的地址,因此被认为是可观察的;它是这样的低级。
在您的特殊情况下,让我们参考标准
expr.log.and逻辑和运算符
&&
运算符从左到右分组.操作数都在上下文上转换为bool
(第4条)。如果两个操作数都是true
,则结果为true
,否则为false
。与&
不同,&&
保证从左到右的计算:如果第一个操作数是false
,则不计算第二个操作数.bool
。如果计算第二表达式,则在每个值计算之前对与第一表达式相关联的每个值计算和副作用进行排序,并对与第二表达式相关的副作用进行排序。这里的关键是(2):排序后/排序前是标准,用于排序可观察的事件。
发布于 2016-06-01 09:36:35
根据标准
5.14逻辑和运算符:
1 &&运算符组从左到右.操作数都在上下文上转换为bool。如果两个操作数为true,否则为false,则结果为true。与&,&& 不同的是,&&保证从左到右计算:如果第一个操作数为false,则不计算第二个操作数。
2结果是一次嘘声。如果计算第二表达式,则将与第一表达式相关联的每一值计算和副作用排序为之前的--每个值计算和与第二表达式相关联的副作用。
因此,根据这些规则,编译器将生成计算function_with_side_effects()
的代码。
https://stackoverflow.com/questions/37575219
复制