10

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()’
4

1 回答 1

8

这是因为析构函数需要 throw() 说明符。如果你没有在你的类中指定它,编译器会为你的类编写它自己的默认析构函数,并且默认析构函数不会指定你不抛出异常。

这是正确的,因为 std::exception 的公共析构函数也指定throw()

~A() throw(){};

来自标准(N3225)12.4.4:

如果一个类没有用户声明的析构函数,则析构函数被隐式声明为 >defaulted (8.4)。隐式声明的析构函数是其类的内联公共成员。

因此,如果您自己不声明析构函数,编译器会创建下一个析构函数。如果所有异常成员析构函数都nothrow合格,编译器可能会生成一个throw()指定的析构函数。

~A(){};

从技术上讲,可以从这个析构函数中抛出异常,但这将是一种非常糟糕的编程风格,因此一个异常源自std::exception保证您不会在std::exception派生类的析构函数中抛出任何异常。

编辑noexcept如果指定了 std::string 的析 构函数,较新的编译器将提供一个具有说明符的析构函数noexceptnoexcept如果所有成员的析构函数都没有抛出异常(noexcept 限定),其他编译器也会生成一个析构函数。这是 C++11 标准在第 15.4 章中规定的。[除了.spec]

14 隐式声明的特殊成员函数(第 12 条)应具有异常规范。如果 f 是隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符或移动赋值运算符,则当且仅当 T 被f 的隐式定义直接调用的函数;如果 f 直接调用的任何函数允许所有异常,则 f 应允许所有异常;如果f 直接调用的每个函数都不允许异常,则 f 应不允许异常。[...]

于 2013-08-24T09:05:10.977 回答