我只是在Compiler Explorer上玩了一些C++代码,在编译一个简单的try
/catch
块时注意到一些意想不到的行为。下面的两个片段都是用gcc使用优化标志-O3
(live example)编译的。
在第一个程序中,整个try
/catch
块被删除,因为在行为上没有明显的差异,导致与return 0;
相同的程序集。这正是我期望编译器产生的结果。
int main() {
try {
int x{ 10 };
}
catch (...) {
}
return 0;
}
个字符
在第二个代码片段中,我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
块是“死代码”(或者不是?),或者如果它能识别它,为什么它没有优化它。
1条答案
按热度按时间8fsztsew1#
第一个例子相当于:
字符串
由于try块中的语句是安全的,编译器检测到catch块永远不会到达,并且它可以通过删除try catch块来进行优化。
在第二个代码段中,你抛出了一个异常,这样try catch块就不是死代码,因为即使它是空的,控件也会进入catch块。
为什么没有优化掉?
虽然catch块中没有执行任何代码,但抛出的异常将继续飞行,除非被catch块显式地处理。因此,执行将进入catch块,然后退出它并将控制(静默)传递给空块后面的代码。