正如标题所说,
一个典型的答案是:
允许任何和所有代码转换不会改变程序的可观察行为的规则
我们会不时地从某些实现中获取行为,这些行为归因于此规则。好多次错了。那么,这条规则究竟是什么呢。标准没有明确地将此规则作为一个部分或段落提及,那么究竟什么属于这条规则的范围?对我来说,这似乎是一个灰色区域,标准没有详细定义。有人可以根据标准的参考资料详细说明细节。
注意:将其标记为C和C ++,因为它与两种语言都相关。
“as-if”规则基本上定义了允许在合法C ++程序上执行的实现的转换。简而言之,允许所有不影响程序“可观察行为”的转换(参见下面的精确定义)。
目标是让实现自由地执行优化,只要程序的行为在抽象机器方面保持符合C ++标准指定的语义。
C ++ 11标准在第1.9 / 1段中引入了“as-if”规则:
本国际标准中的语义描述定义了参数化的非确定性抽象机器。本国际标准对符合实施的结构没有要求。特别是,它们不需要复制或模拟抽象机器的结构。相反,需要符合实现来模拟(仅)抽象机器的可观察行为,如下所述。
另外,一个解释性脚注补充说:
这项规定有时被称为“假设”规则,因为只要结果就像是遵守了要求,只要可以从可观察的行为中确定,实施就可以自由地忽视本国际标准的任何要求。该计划。例如,实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用,并且没有产生影响程序的可观察行为的副作用。
第1.9 / 5段进一步规定:
执行格式良好的程序的一致实现应该产生与具有相同程序和相同输入的抽象机的相应实例的可能执行之一相同的可观察行为。但是,如果任何此类执行包含未定义的操作,则此国际标准不要求使用该输入执行该程序的实现(甚至不考虑第一个未定义操作之前的操作)。
值得强调的是,这种约束仅在“执行格式良好的程序”时适用,并且执行包含未定义行为的程序的可能结果不受约束。第1.9 / 4段也明确说明了这一点:
本国际标准中将某些其他操作描述为未定义(例如,尝试修改const对象的效果)。 [注意:本国际标准对包含未定义行为的程序的行为没有要求。 - 尾注]
最后,关于“可观察行为”的定义,第1.9 / 8段如下:
符合实施的最低要求是:
- 严格根据抽象机的规则来评估对易失性对象的访问。
- 在程序终止时,写入文件的所有数据应与根据抽象语义产生的程序执行的可能结果之一相同。
- 交互设备的输入和输出动态应以在程序等待输入之前提示输出实际传送的方式进行。构成交互设备的是实现定义的。
这些统称为程序的可观察行为。 [注意:每个实现可以定义抽象和实际语义之间更严格的对应关系。 - 尾注]
据我所知,“as-if”规则的唯一例外是复制/移动省略,即使复制构造函数,移动构造函数或类的析构函数具有副作用,也允许使用复制/移动省略。确切的条件在第12.8 / 31段中规定:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用。 [...]
在C11中,规则永远不会被该名称调用。然而,C,就像C ++一样,用抽象机器来定义行为。 as-if规则在C11 5.1.2.3p4 and p6中:
- 在抽象机器中,所有表达式都按语义指定进行计算。实际实现不需要评估表达式的一部分,如果它可以推断出它的值未被使用并且不产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用)。
- [...]
- 符合实施的最低要求是: 根据抽象机器的规则严格评估对
volatile
对象的访问。 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序的结果相同。 交互设备的输入和输出动态应按照7.21.3的规定进行。这些要求的目的是尽快出现无缓冲或行缓冲输出,以确保在程序等待输入之前实际出现提示消息。 这是该程序的可观察行为。