在C ++中,您可以使用以下异常规范声明函数:
int foo() const throw(Exception);
我找到了这两个链接:
但有几件事最终没有答案......
问题1:为什么要添加异常规范?它会带来任何性能提升吗?编译器会有什么不同?因为它似乎就像程序员的信息一样。
问题2:如果我扔掉一些不符合规格的东西会发生什么(会发生什么)?例如:
int foo() throw(int) {
throw char; // Totally unrelated classes, not types in real
}
问题3:函数/方法不应该抛出任何东西。我发现至少有两种(不同编译器的三种替代语法)指定无异常抛出的方法:
int foo() throw();
int foo() __attribute(nothrow)__
for gcc int foo() nothrow
for visual C ++ 哪一个是“正确的”?有什么区别吗?我应该使用哪一个?
问题4:“标准例外”,bad_alloc
,bad_cast
,bad_exception
,bad_typeid
和ios_base::failure
。
好的bad_alloc
是自我解释的,我知道如何(更重要的是何时)使用它(添加到异常规范),但其他的呢?他们都没有真正响铃......他们与哪些“代码片段”相关联?例如,bad_alloc
与new char[500000]
相关联。
问题5:如果我有异常类层次结构,请执行以下操作:
class ExceptionFileType {
virtual const char * getError() const = 0;
};
class ExceptionFileTypeMissing : public ExceptionFileType {
virtual const char *getError() cosnt {
return "Missing file";
}
}
我应该使用:
int foo() throw(ExceptionFileType);
或者:
int foo() throw(ExceptionFileTypeMissing,ExceptionFileTypeNotWritable,ExceptionFileTypeNotReadable,...)
注意:带参考的答案会很棒。我正在寻找好的练习技巧。
答案 0 :(得分:6)
简单的良好做法"提示是:不要使用异常规范。
基本上唯一的例外是可能出现空的异常规范:throw()
。这非常有用,在C ++ 11中它被赋予了自己的关键字(noexcept
)。它普遍认为,任何非空的异常规范都是一个糟糕的想法。
异常规范(noexcept
除外)已被正式弃用 - 与许多已弃用的功能不同,删除此功能会影响到我认为最不足的源代码,最终有可能将其删除(当然不能保证,但无论如何都是相当公平的机会。)
当/如果你抛出异常规范不允许的类型的异常时会发生什么:std::unexpected()
被调用。默认情况下,它会调用terminate()
。您可以使用std::set_unexpected
设置自己的处理程序 - 但您可以合理地做的就是在terminate()
之前添加一些日志记录。您的意外处理程序不允许返回。
答案 1 :(得分:3)
问题1
不要打扰。他们是一个坏主意,并在最新版本的语言中被弃用。它们对编译器没有任何好处,因为它们在运行时被检查;如果有的话,在某些情况下它们可能会损害性能。
问题2
将调用名为std::unexpected
的函数。默认情况下,这会调用std::terminate
;默认情况下,终止程序。如果您真的想要,可以使用std::set_unexpected
和std::set_terminate
来安装自己的处理程序,从而更改这两种行为。
问题3
throw()
是执行此操作的标准方式;其他是非可移植的编译器扩展。在C ++ 11中,您可以使用noexcept
,它提供编译时检查,没有任何东西可以抛出,而不是运行时检查没有任何东西抛出。
问题4
bad_cast
引用失败时,抛出dynamic_cast
。bad_exception
会在某些奇怪的情况下抛出。bad_typeid
的参数涉及取消引用空指针,则抛出typeid
当某些操作失败时,输入/输出库(ios_base::failure
等)抛出<iostream>
问题5
如果要允许抛出整个层次结构,则只需指定基类。但是你根本不应该使用异常说明符。
答案 2 :(得分:2)
首先,让我们非常清楚异常规范的作用:它是
或多或少像assert
无法禁用,断言你
除了其他之外,不会退出该功能
失踪。因此,它的效用远比看上去有限
首先;在大多数情况下(在这种情况下,我无法想象一个
例外),唯一真正有用的保证是throw()
,其中
保证不会抛出任何异常;如果你想写
异常安全的代码,你需要这个保证几个低级别
功能
实际上,虽然throw()
可以允许一些额外的编译器
优化,通用实现往往导致更少
使用异常规范时的高效代码。在C ++ 11中,
throw()
已被noexcept
取代,大概希望如此
编译器实现者会用它做一些聪明的事情。
编辑:
因为每个人(包括我自己)似乎都错过了你的问题4:
如果不能,bad_alloc
函数将抛出 operator new
分配内存。
bad_cast
将被dynamic_cast
引用到引用中
演员表演失败的情况。 (指针的dynamic_cast
返回一个
在这种情况下,空指针。)
bad_exception
如果异常规范允许bad_exception
,则违反。
(换句话说,算了吧。)
bad_typeid
与null一起使用,则会抛出 typeid
指针。
ios_base::failure
如果出现错误。
实际上说:如果你想要恢复,你会抓住bad_alloc
并从内存不足的情况继续。这意味着不常见。
(从内存不足的情况中恢复是非常非常困难的。)
对于bad_cast
,它可能更适合使用指针,并测试
null,如果你不确定。没有任何借口可以看到一个
bad_typeid
。大多数情况下,您可能希望测试IO错误
显式,而不是配置流来抛出异常;和
设置ios_base::badbit
时的异常可能是异常(因为它
代表了一个真正特殊的例外情况。
答案 3 :(得分:1)
问题1和问题2在this question中得到了很长的解决。
问题3和5涵盖在该问题的公认答案中,您根本不使用例外规范。
问题4似乎可以通过在您选择的搜索引擎中键入这些异常名称或查阅优秀C ++书籍的索引来得到充分解决。你对它们有具体的询问吗?