关于例外规范和应用设计的问题

时间:2012-06-15 13:25:11

标签: c++ design-patterns exception exception-handling try-catch

虽然这个主题已在SO上进行了广泛的讨论,但我想澄清一些对我来说仍然不清楚的事情,考虑到以下事实:

  1. 10年前,Herb Sutter告诉我们refrain from using this functionality

  2. 指定函数/方法可能抛出的异常并不会强迫编译器在您决定更改函数体并抛出新类型的异常时向您大喊,忘记更改异常规范在函数的声明中。

  3. 如果你有一个非常高级别的函数调用其他几个高级函数,每个函数运行大量的代码来产生结果,那么我可以想象从地狱噩梦中维护,当我必须指定ALL时第一个函数可能抛出的错误,这个列表必须包括内部函数可能抛出的所有异常,等等,从而在高级和低级函数之间产生紧密耦合,这是非常不希望的。另一方面,我们从std :: runtime_error派生所有异常,we know is a good practice我们可以指定高级函数只抛出std :: runtime_error并完成它。但是等一下......我们在哪里实际捕获异常?在高级函数应该只抛出std :: runtime_error时,在try / catch块中包含对其中一个高级函数的调用是不是很奇怪/讨厌/坏,这会捕获一个MyVerySpecific异常。 ?在较低级别的函数中捕获特定异常会不会有任何好处,这些函数不能对它们做任何事情,而是在更通用的容器中传递它们,并附加更多信息?我当然不想在我编写的每个函数中编写try / catch块,只是为了格式化异常。这就像要求每个功能验证其参数一样,当他们需要在低级功能中更改某些内容时,这可能会让人感到疯狂。

  4. 问题:

    1. Herb Sutter关于异常规范的咆哮今天仍然存在吗?从那时起有什么变化吗?我最感兴趣的是前C ++ 0x标准。如果是,我想我们可以考虑关闭这个话题。

    2. 由于编译器似乎主要忽略这些异常规范,并且在捕获异常时,在99%的情况下,会使用catch (const CustomException &ex),如何指定函数抛出CustomException? throw(CustomExecption)throw (CustomException &)throw (const CustomException &)?我已经看到了所有的变化,虽然我会选择第一个,但其他人是否有任何意义/增加任何好处?

    3. 如何实际使用此功能,同时避免上述第三个事实中所述的谬误?

    4. 编辑:假设我们正在构建一个库。如果我们不使用异常规范,它的用户将如何知道期望的异常?他们肯定不会看到API方法将在内部调用哪些函数......

2 个答案:

答案 0 :(得分:2)

  

1 / Herb Sutter关于异常规范的咆哮今天仍然存在吗?从那时起有什么变化吗?我最感兴趣的是前C ++ 0x标准。如果是,我想我们可以考虑关闭这个主题。

是的,他们仍然坚持。

例外规格如下:

  • 中途实现(例如,函数指针不指定异常)
  • 未在编译时检查,但导致在运行时终止!!

一般情况下,我会反对异常规范,因为它会导致实现细节的泄漏。看看Java异常的状态......

特别是在C ++中?例外规范就像在脚下拍摄自己,因为文档中最微小的错误可能导致std::terminate电话。请注意,几乎所有函数都可能会抛出std::bad_allocstd::out_of_range

注意:自C ++ 11以来,throw()已被弃用,现在使用C ++ 17它已经不见了;相反,从C ++ 17开始,可以使用noexcept(false)说明符。它在函数指针中得到了更好的支持,但仍然导致在运行时终止而不是在编译时出错。


  

2 /由于似乎编译器大多忽略了这些异常规范,并且在捕获异常时,在99%的情况下,一个会使用catch(const CustomException& ex),如何指定一个函数抛出CustomException ? throw(CustomExecption)或throw(CustomException&)或throw(const CustomException&)?我已经看到了所有的变化,虽然我会选择第一个,但其他人是否有任何意义/增加任何好处?

编译器不会忽略异常规范,它会设置非常警惕的监视器(哪些轴)以确保在您遗漏某些内容时终止程序。


  

3 /如何实际使用此功能,同时避免上述第三个事实中所述的谬误?

如果客户保持非正式,您的客户会很感激,所以最好的例子是:

void func(); // throw CustomException

这使您可以专注于重要的异常,并让“不重要”的例外漏掉。如果消费者想要他们所有? catch(std::exception const& e)有效。


  

4 /编辑:假设我们正在建立一个图书馆。如果我们不使用异常规范,它的用户将如何知道期望的异常?他们肯定不会看到API方法将在内部调用哪些函数......

他们必须吗?

记录重要的事项,std::exception...处理意外情况。

答案 1 :(得分:0)

  
      
  1. Herb Sutter关于异常规范的咆哮今天仍然存在吗?从那时起有什么变化吗?
  2.   

我不会称之为咆哮。他只是指出了与异常规范有关的问题。

是的,它仍然有效。如文中所述,如果抛出未指定的异常,程序将终止,99%的应用程序无法接受。

  
      
  1. 如何指定函数抛出CustomException?
  2.   
class A
{
 //...
   void foo() throws( CustomException );
};
  
      
  1. 如何实际使用此功能,同时避免上述第三个事实中所述的谬误?
  2.   

通过查看函数声明,用户知道可以抛出哪些异常。问题是当需要抛出新的异常时,需要更改所有函数声明。

  
      
  1. 假设我们正在构建一个库。如果我们不使用异常规范,它的用户将如何知道期望的异常?
  2.   

阅读文档。