gcc默认析构函数的异常规范

Yor*_*lov 8 c++ linux gcc exception throw

class A
{
    public:
    virtual ~A()
    {
    }
};

class B : virtual public A
{
    public:
    ~B() throw()
    {}
};

class C : public B
{
};

int main(int argc, char * argv [])
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)

该代码给出以下错误:

error: looser throw specifier for ‘virtual C::~C()’
error:   overriding ‘virtual B::~B() throw ()’
Run Code Online (Sandbox Code Playgroud)

在我的debian测试中(gcc(Debian 4.6.0-10)4.6.1 20110526(预发布))但在先前的gcc版本上编译没有错误(我的debian系统再次4.5).

异常规范如何影响虚拟析构函数覆盖? 根据该答案,编译器应该创建一个与基类的throw声明匹配的默认构造函数.显然这不是新gcc上发生的事情.什么是改变,什么是正确的编译器行为,除了在派生类中手动添加空析构函数(例如编译器标志)之外,还有一些简单的解决方案.

Ala*_*kes 3

我认为在实际代码中要么~A()要么~B()被声明为虚拟?(错误消息抱怨虚拟析构函数,但在编写的代码中没有一个析构函数是虚拟的。)

我相信虚拟继承是引发您问题的原因。C 的(隐式定义的)析构函数需要首先调用~B(),然后(因为 C 是最派生类)调用~A(). (12.4/6)

生成的异常规范~C()需要允许任何异常传播,因为它直接调用~A()没有异常规范的which。(15.4/13)

然后就会触发你的错误 - 你不能用可能抛出异常的throw()版本的规范(B的析构函数)覆盖虚拟函数。(15.4/3)

解决方案是放置throw()A 的析构函数。(如果你做不到,那你为什么要在 B 上做呢?)

如果没有虚拟继承,该错误也不会发生 - 因为这样 C 的析构函数只会调用 B 的析构函数。(B 的析构函数仍然会调用 A 的析构函数,而你仍然如履薄冰,因为如果 A 的析构函数抛出异常,你将直接转到terminate()。)