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

时间:2011-06-30 17:56:57

标签: c++ linux exception gcc 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;
}

该代码出现以下错误:

error: looser throw specifier for ‘virtual C::~C()’
error:   overriding ‘virtual B::~B() throw ()’

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

How does an exception specification affect virtual destructor overriding? 根据该答案,编译器应该创建一个与基类的throw声明匹配的默认构造函数。显然这不是新gcc上发生的事情。更改了什么,正确的编译器行为是什么,除了在派生类中手动添加空析构函数(例如编译器标志)之外,还有一些简单的解决方案。

2 个答案:

答案 0 :(得分:3)

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

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

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

然后会触发您的错误 - 您无法使用可能抛出的版本覆盖具有throw()规范(B的析构函数)的虚函数。 (15.4 / 3)

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

如果没有虚拟继承,也不会发生错误 - 因为C的析构函数只会调用B的析构函数。 (B的析构函数仍然会调用A - 而你仍然在薄冰上滑行,因为如果A的析构函数抛出你直接进入terminate()。)

答案 1 :(得分:0)

GCC 4.X比以前的版本更严格,因此可能无法隐式声明。尝试明确说明。

我理解它的方式,如果B类有一个明确没有扔掉的析构函数(即

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

应该没问题。

无论如何,上次我检查过这种做法是非常糟糕的做法,以便从d'tors中抛出异常。

希望有所帮助!