如果注释line 8
,则以下程序无法在g ++ 4.4中编译。为什么?似乎当我重写std::exception
构造函数时,我也必须覆盖它的析构函数。这是什么原因?
#include<iostream>
#include<exception>
using namespace std;
class A : public exception {
public:
A(string msg) : _msg(msg) {}
//~A() throw(){}; // line 8
const char* what() const throw() { return _msg.c_str();}
private:
string _msg;
};
int main()
{
}
编译错误是:
error: looser throw specifier for ‘virtual A::~A()’
答案 0 :(得分:8)
这是因为析构函数需要throw()说明符。如果你没有在你的类中指定它,编译器会为你的类编写它自己的默认析构函数,而默认的析构函数并没有指定你不抛出异常。
这是正确的,因为std :: exception的公共析构函数也指定了throw()
~A() throw(){};
来自标准(N3225)12.4.4:
如果一个类没有用户声明的析构函数,则析构函数被隐式声明为&gt; defaultaulted(8.4)。隐含地 - 声明的析构函数是其类的内联公共成员。
因此,如果您不自己声明析构函数,编译器将创建下一个析构函数。如果nothrow
符合条件的所有异常成员析构函数,编译器可能会生成一个指定了throw()
的析构函数。
~A(){};
从技术上讲,可以从这个析构函数中抛出一个异常,但这样编程样式会非常糟糕,因此从std::exception
派生的异常可以保证你不会在{{1}的析构函数中抛出异常派生类。
修改的
如果指定std :: string的析构函数为std::exception
,则较新的编译器将提供具有noexcept
说明符的析构函数。如果所有成员的析构函数都不抛出异常(noexcept限定),其他编译器也会生成noexcept
析构函数。
这是第15.4章中C ++ 11标准的强制要求。 [except.spec]
14隐式声明的特殊成员函数(第12条)应具有例外规范。 如果f是 隐式声明的默认构造函数,复制构造函数,移动构造函数,析构函数,复制赋值 运算符,或移动赋值运算符,其隐式异常规范指定了type-id T if和only 如果由f的隐式定义直接调用的函数的异常规范允许T; f 允许所有异常,如果它直接调用的任何函数允许所有异常, f将不允许异常 如果它直接调用的每个函数都不允许例外。 [...]