抛出异常是由抽象机评估的吗?

cig*_*ien 1 c++ exception throw language-lawyer semantics

根据intro.abstract#1

...需要一致的实现来模拟(仅)抽象机的可观察行为,如下所述。

这个解释就是as-if 规则,其中包含以下示例:

...如果实际实现可以推断出其值未被使用并且不会产生影响程序可观察行为的副作用,则实际实现不需要评估表达式的一部分。

副作用的定义在intro.execution#7中:

读取由易失性泛左值 ([basic.lval]) 指定的对象、修改对象、调用库 I/O 函数或调用执行任何这些操作的函数都是副作用,即状态的更改执行环境。...

在我看来,在以下程序中:

int main() 
{
  throw 42;
}
Run Code Online (Sandbox Code Playgroud)

表达式的值throw 42;未被使用,并且它不满足任何副作用的标准。

这是否意味着允许实现不评估该表达式?上述程序是否等价于:

int main() {}
Run Code Online (Sandbox Code Playgroud)

就抽象机而言?我找不到任何说明抽象机器知道或关心异常的文本。

dxi*_*xiv 6

(编辑过的)问题归结为是否允许编译器“优化”int main() { throw 42; }int main() { }. 我相信在这种情况下答案是否定的,因为抛出的异常会导致程序的可观察行为发生变化,而编译器需要模拟这种变化。

由于没有定义显式处理程序,throw 42;因此应该调用std::terminate()该处理程序,进而最终调用std::abort(),其中“将实现定义的状态返回到指示执行不成功的主机环境”。换句话说,程序的退出代码与不抛出异常的情况下是不同的,因此不能throw省略。

(这排除了独立实现的情况,其中没有“主机”可返回,但我认为不允许编译器对其运行环境做出假设。)

在更一般的情况下,当用户代码中定义了显式匹配的异常处理程序时,它会变得更加模糊。抛出异常会将控制权转移给该处理程序,但如果编译器可以确定该处理程序不会导致可观察行为其他副作用的变化,那么整个过程throw 可能会被优化。如果处理程序不访问任何易失性数据、不修改任何对象、不调用任何库 I/O 函数并执行与正常退出等效的程序退出,则可能会发生这种情况。

  • @curiousguy在我的阅读中,问题*是*关于“*表达式`throw 42;`*”,没有定义处理程序,即未捕获的异常。可观察到的行为只是“假设”的另一种表达方式。 (3认同)