我只是在 Compiler Explorer 上玩一些 C++ 代码,并在编译简单的
try
/catch
块时注意到一些意外的行为。以下两个片段都是使用 gcc 使用优化标志 -O3
进行编译的(现场示例)。
在第一个程序中,整个
try
/catch
块被删除,因为行为上没有明显的差异,导致与 return 0;
相同的组件。这正是我期望编译器产生的结果。
int main() {
try {
int x{ 10 };
}
catch (...) {
}
return 0;
}
main:
xor eax, eax
ret
在第二个片段中,我
throw
是一个异常,而不是仅仅初始化 int
。抛出该异常后,我将继续使用 catch
-all 处理程序,该处理程序是空的。之后就只有 return 0;
语句了。这意味着该程序的可观察行为将与第一个程序相同。然而,大会表明,整个 try
/catch
仍在继续。
int main() {
try {
throw 10;
}
catch (...) {
}
return 0;
}
main:
push rcx
mov edi, 4
call __cxa_allocate_exception
xor edx, edx
mov esi, OFFSET FLAT:_ZTIi
mov DWORD PTR [rax], 10
mov rdi, rax
call __cxa_throw
mov rdi, rax
call __cxa_begin_catch
call __cxa_end_catch
xor eax, eax
pop rdx
ret
现在我想知道为什么编译器无法识别整个
try
/catch
块是“死代码”(或者不是?),或者如果它可以识别它,为什么它不优化它.
第一个例子相当于:
int main() {
int x{ 10 };
return 0;
}
由于try块中的语句是安全的,编译器会检测到永远不会到达catch块,并且可以通过摆脱try catch块来进行优化。
在第二个代码片段中,您抛出了一个异常,因此 try catch 块不是死代码,因为控件将进入 catch 块,即使它是空的。
虽然catch块中没有执行任何代码,但抛出的异常将继续运行,除非catch块显式处理并捕获该异常。因此,执行将进入 catch 块,然后从中退出,并将控制权(默默地)传递给该空块后面的代码。