C ++为已检查的异常提供语法,例如:
void G() throw(Exception);
void f() throw();
但是,Visual C ++编译器不检查它们; throw标志被忽略了。在我看来,这使得异常功能无法使用。所以我的问题是: 有没有办法让编译器检查异常是否被正确捕获/重新抛出? 例如Visual C ++插件或不同的C ++编译器。
PS。我希望编译器检查异常是否被正确捕获,否则你最终会遇到一个问题,即你必须在每个函数调用中设置一个catch,即使它们明确声明它们不会抛出任何东西> EM>
更新:当引入标有throw()的函数时,Visual C ++编译器会显示警告。这很好,但令人遗憾的是,当你调用可能抛出的子程序时,警告不会出现。例如:
void f() throw(int) { throw int(13); }
void h() throw() { g(); } //no warning here!
答案 0 :(得分:38)
有趣的是Java检查了异常,Java程序员也讨厌这些异常。
C ++中的异常规范没有用,原因有三个:
<强> 1。 C ++异常规范禁止优化。
除了throw()之外,编译器会插入额外的代码来检查当你抛出异常时,它会在堆栈展开期间匹配函数的异常规范。让你的程序变慢的方法。
<强> 2。 C ++异常规范不是编译器强制的
就编译器而言,以下语法正确:
void AStupidFunction() throw()
{
throw 42;
}
更糟糕的是,如果违反异常规范,没有任何有用的事情发生。你的程序刚刚终止!
第3。 C ++异常规范是函数签名的一部分。
如果您有一个带有虚函数的基类并尝试覆盖它,那么异常规范必须完全匹配。所以,你最好提前计划,这仍然很痛苦。
struct A
{
virtual int value() const throw() {return 10;}
}
struct B : public A
{
virtual int value() const {return functionThatCanThrow();} // ERROR!
}
异常规范会给您带来这些问题,并且使用它们的收益很小。相反,如果你完全避免异常规范,编码会更容易,你可以避免这种情况。
答案 1 :(得分:30)
在C ++中,异常规范是无用的。
没有强制执行不抛出其他异常,而只是调用全局函数unexpected()
(可以设置)
使用异常规范主要归结为将自己(或同伴)欺骗成一种虚假的安全感。最好不要打扰。
答案 2 :(得分:15)
看看这个:
http://www.gotw.ca/publications/mill22.htm
基本上异常规范是不可行的/不可用的,但这并不会使异常变得不可行。
至于你的问题,没有办法让编译器检查抛出的每个类型都被捕获到代码中更高的位置,我希望编译单元使这很困难,并且不可能对要用于的代码执行此操作库(在编译时顶层不可用)。如果你想确保所有东西都被捕获,那么在代码的最顶部贴一个catch(...)。
答案 3 :(得分:9)
在运行时案例之前检测,例如......
extern void f() throw (class Mystery);
void g() throw() {
f() ;
}
...您需要静态分析。是的,编译器正在进行大量的静态分析,但是因为标准是“如果throw不匹配就引发std :: unexpected”,编写一个抛出与说明符不匹配的对象的例程是完全合法的。 ,编译器实现者既不警告也不评论。
声称提供警告服务的静态分析工具包括Gimpel Software的lint for C++ ...
1560未捕获的异常'名称'不在函数'Symbol'的抛出列表中
并根据this answer对先前的问题QA C++。
答案 4 :(得分:8)
因为标准是这样说的。异常声明并不意味着不会抛出其他异常。这意味着如果抛出未声明的异常,将会调用一个名为 unexpected()的特殊全局函数,该函数默认终止该程序。通常不鼓励在函数中声明异常(可能除了空例外列表),因为标准行为不是很有帮助。
答案 5 :(得分:0)
我无法检查这是否缺少MSVC安装,但你真的确定编译器会忽略throw()规范吗?
This MSDN page表明Microsoft知道throw()并期望他们的编译器正确处理它。好吧,差不多,请看一些关于它们如何脱离ANSI / ISO标准的说明。
编辑:但实际上,我同意Patrick:异常规范大多没用。