为什么编译器没有检查C++中的异常?

Dim*_* C. 42 c++ exception visual-c++

C++为已检查的异常提供了语法,例如:

void G() throw(Exception);
void f() throw();
Run Code Online (Sandbox Code Playgroud)

但是,Visual C++编译器不检查它们; throw标志被忽略了.在我看来,这使得异常功能无法使用.所以我的问题是:有没有办法让编译器检查异常是否被正确捕获/重新抛出?例如,Visual C++插件或不同的C++编译器.

PS.我希望编译器检查异常是否被正确捕获,否则你最终会遇到必须对每个函数调用进行捕获的情况,即使它们明确声明它们不会抛出任何东西.

更新:当抛出标有throw()的函数时,Visual C++编译器确实显示警告.这很好,但令人遗憾的是,当你调用可能抛出的子程序时,警告不会出现.例如:

void f() throw(int) { throw int(13); }
void h() throw() { g(); } //no warning here!
Run Code Online (Sandbox Code Playgroud)

rlb*_*ond 39

有趣的是Java检查了异常,Java程序员也讨厌这些异常.

C++中的异常规范是无用的,原因有三个:

1. C++异常规范禁止优化.

除了throw()之外,编译器会插入额外的代码来检查当你抛出异常时,它会在堆栈展开期间匹配函数的异常规范.让你的程序变慢的方法.

2. C++异常规范不是编译器强制执行的

就编译器而言,以下语法正确:

void AStupidFunction() throw()
{
    throw 42;
}
Run Code Online (Sandbox Code Playgroud)

更糟糕的是,如果你违反了异常规范,没有任何用处.你的程序刚刚终止!

3. C++异常规范是函数签名的一部分.

如果您有一个带有虚函数的基类并尝试覆盖它,那么异常规范必须完全匹配.所以,你最好提前计划,这仍然很痛苦.

struct A
{
    virtual int value() const throw() {return 10;}
}

struct B : public A
{
    virtual int value() const {return functionThatCanThrow();} // ERROR!
}
Run Code Online (Sandbox Code Playgroud)

异常规范为您提供了这些问题,使用它们的收益很小.相反,如果您完全避免异常规范,编码会更容易,您可以避免这种情况.

  • 实际上作为一个Java程序员,我不讨厌检查异常,我实际上喜欢它,它可以在很多情况下避免许多潜在的问题. (5认同)

Pie*_*ter 30

在C++中,异常规范是无用的.

没有强制执行任何其他异常,而只是unexpected()调用全局函数(可以设置)

使用异常规范主要归结为将自己(或同伴)欺骗成一种虚假的安全感.最好不要打扰.

  • “不可能”是一个非常强烈的主张。为什么模板无法执行异常规范? (2认同)
  • 正确的观点,但完全错误的论点。C++(与 Java 和大多数其他现代语言不同)在运行时而不是编译时检查异常规范。不幸的是,异常规范中的这个实验没有起作用(除了没有抛出)。 (2认同)

Pat*_*ick 15

看看这个:

http://www.gotw.ca/publications/mill22.htm

基本上异常规范是不可行的/不可用的,但这并不会使异常变得不可行.

至于你的问题,没有办法让编译器检查抛出的每个类型都被捕获到代码中更高的位置,我希望编译单元使这很困难,并且不可能为要在库中使用的代码执行此操作(顶层在编译时不可用的地方).如果你想确保一切都被捕获,那么在代码的最顶部粘上一个catch(...).


Tho*_*day 9

在运行时案例之前检测,例如......

extern void f() throw (class Mystery);
void g() throw() { 
    f() ; 
}
Run Code Online (Sandbox Code Playgroud)

......你需要静态分析.是的,编译器正在进行大量的静态分析,但是因为标准是"如果throw不匹配就引发std :: unexpected",编写一个抛出与说明符不匹配的对象的例程是完全合法的. ,编译器实现者既不警告也不评论.

声称提供警告服务的静态分析工具包括Gimpel Software的C++ lint ...

1560未捕获的异常'名称'不在函数'Symbol'的throw-list上

并且,根据先前问题的答案,QA C++.


Tad*_*pec 8

因为标准是这样说的.异常声明并不意味着不会抛出其他异常.这意味着如果抛出未声明的异常,将会调用一个名为unexpected()的特殊全局函数,该函数默认终止该程序.通常不鼓励在函数中声明异常(可能除了空的异常列表),因为标准行为不是很有用.