覆盖std的析构函数:异常

时间:2013-08-24 09:02:03

标签: c++ exception exception-handling destructor throw

如果注释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()’

1 个答案:

答案 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将不允许异常   如果它直接调用的每个函数都不允许例外。 [...]