在函数签名中使用c++ throw关键字被认为是坏习惯的技术原因是什么?

bool some_func() throw(myExc)
{
  ...
  if (problem_occurred) 
  {
    throw myExc("problem occurred");
  }
  ...
}

当前回答

不,这被认为是不好的做法。相反,它通常被认为是一个坏主意。

http://www.gotw.ca/publications/mill22.htm详细介绍了原因,但问题部分在于编译器无法强制执行,因此必须在运行时进行检查,这通常是不可取的。而且它在任何情况下都没有得到很好的支持。(MSVC忽略异常规范,但throw()除外,它将其解释为保证不会抛出异常。

其他回答

不,这被认为是不好的做法。相反,它通常被认为是一个坏主意。

http://www.gotw.ca/publications/mill22.htm详细介绍了原因,但问题部分在于编译器无法强制执行,因此必须在运行时进行检查,这通常是不可取的。而且它在任何情况下都没有得到很好的支持。(MSVC忽略异常规范,但throw()除外,它将其解释为保证不会抛出异常。

当将throw规范添加到语言中时,它是出于最好的意图,但实践证明了一种更实用的方法。

在c++中,我的一般经验法则是只使用抛出规范来指示一个方法不能抛出。这是一个强有力的保证。否则,假设它可以抛出任何东西。

抛出说明符的唯一实际效果是,如果你的函数抛出了与myExc不同的东西,std::unexpected将被调用(而不是正常的未处理异常机制)。

为了记录函数可以抛出的异常类型,我通常这样做:

bool
some_func() /* throw (myExc) */ {
}

Jalf已经链接到它了,但是GOTW很好地解释了为什么异常规范没有人们希望的那么有用:

int Gunc() throw();    // will throw nothing (?)
int Hunc() throw(A,B); // can only throw A or B (?)

这些评论正确吗?不完全是。Gunc()可能确实会扔东西,而Hunc()很可能会扔A或B以外的东西!如果它们这样做,编译器只会保证把它们打得毫无意义……哦,大多数情况下,也会把你的程序打得毫无意义。

这就是最终的结果,您可能只会调用terminate(),并且您的程序会快速但痛苦地死亡。

GOTWs的结论是:

因此,以下似乎是我们作为一个社区到目前为止学到的最好的建议: 寓意#1:永远不要编写异常规范。 寓意2:可能除了一个空的,但如果我是你,我甚至会避免这样做。

为了给这个问题的其他答案增加一点价值,你应该在这个问题上花几分钟: 下面代码的输出是什么?

#include <iostream>
void throw_exception() throw(const char *)
{
    throw 10;
}
void my_unexpected(){
    std::cout << "well - this was unexpected" << std::endl;
}
int main(int argc, char **argv){
    std::set_unexpected(my_unexpected);
    try{
        throw_exception();
    }catch(int x){
        std::cout << "catch int: " << x << std::endl;
    }catch(...){
        std::cout << "catch ..." << std::endl;
    }
}

答:正如这里所指出的,程序调用std::terminate(),因此不会调用任何异常处理程序。

详细信息:第一个my_unexpected()函数被调用,但由于它不会为throw_exception()函数原型重新抛出匹配的异常类型,因此最后调用std::terminate()。所以完整的输出是这样的:

user@user:~/tmp$ g++ -o except。测试except.test.cpp user@user: ~。美元/ tmp / except.test 嗯——这是出乎意料的 抛出'int'实例后调用的终止 中止(核心转储)