【发布时间】:2023-03-16 03:17:02
【问题描述】:
我正在使用包含很多 try catch 块的代码,但大多数情况下 catch 块什么都不做。如下面的代码中fib 函数正在抛出invalid_argument 异常。 main 中的函数调用在 try 块中,但 catch 块除了捕获异常之外什么都不做。
我想知道编译器是否会在代码优化期间去掉这种异常处理?
#include <iostream>
#include <exception>
// Declaration for Wmissing-declarations flag
int fib(int);
int fib(int n)
{
if (n < 0)
{
throw std::invalid_argument("Invalid argument");
}
if (n == 0 || n == 1)
return n;
return fib(n-1) + fib(n-2);
}
int main(int argc, char *argv[])
{
int _number;
std::cin >> _number;
try
{
std::cout << fib(_number) << std::endl;
}
catch(const std::invalid_argument & e)
{
}
return 0;
}
在打开大多数(我所知道的)标志的情况下编译上面的代码,如下所示,不会显示任何警告。
g++ -o except exceptions.cxx -pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused
【问题讨论】:
-
存在捕获这一事实确保了异常被捕获。否则它将立即终止此功能以及可能许多其他功能,并且很可能会导致程序终止。它最终会导致程序返回非零值 - 用户外部的错误代码信息,表明程序中发生错误。但是,这些被捕获并返回 0。
-
编译器无法删除
catch作为优化,因为这会改变程序的行为。除了极少数和特定的情况外,优化永远不允许改变可观察的行为。它也不能删除throw,因为如果n < 0,函数fib不能被允许return。 -
一个完美的编译器可以被允许“重写”你的程序以在不使用
throw std::invalid_argument("Invalid argument");的情况下具有相同的可观察行为,但这对你来说一定是察觉不到的(就行为而言)。所以真正的问题是为什么你特别关心异常是否被优化?你怎么知道区别?这可能是 XY 问题。 -
编译器至少必须展开堆栈。鉴于
fib在必须展开的递归调用中有两个临时变量,并且编译器不知道fib将从什么堆栈深度抛出,仅此一项就排除了删除。 godbolt.org/z/v37n6rxba -
问题的前提是错误的:一个空的
try...catch块不会什么都不做。
标签: c++ performance c++11 error-handling c++20