gcc спецификация исключения деструктора по умолчанию - PullRequest
8 голосов
/ 30 июня 2011
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 (prerelease)), но компилируется без ошибок в предыдущемВерсии gcc (4.5 в моей системе Debian снова).

Как спецификация исключений влияет на переопределение виртуального деструктора? Согласно этому ответу компилятор должен создать конструктор по умолчанию, соответствующий объявлению броска базового класса.Очевидно, что это не то, что происходит на новом GCC.Что изменилось, каково правильное поведение компилятора и есть ли простое решение проблемы, кроме ручного добавления пустых деструкторов в производные классы (например, флаг компилятора).

Ответы [ 2 ]

3 голосов
/ 20 июля 2011

Я предполагаю, что в реальном коде ~A() или ~B() объявлено виртуальным? (Сообщение об ошибке жалуется на виртуальный деструктор, но в написанном коде ни один из деструкторов не является виртуальным.)

Я полагаю, что виртуальное наследование является причиной вашей проблемы. Деструктор C (неявно определенный) должен сначала вызвать ~B(), а затем, поскольку C является наиболее производным классом, вызвать ~A(). (12.4 / 6)

Сгенерированная спецификация исключения для ~C() требуется, чтобы разрешить распространение любого исключения, потому что оно напрямую вызывает ~A(), который не имеет спецификации исключения. (15,4 / 13)

И это тогда вызывает вашу ошибку - вы не можете переопределить виртуальную функцию со спецификацией throw() (деструктор B) с версией, которая может выдать. (15,4 / 3)

Решением было бы поставить throw() на деструктора А. (Если вы не можете этого сделать, то почему вы делаете это на B?)

Ошибка также не произошла бы без виртуального наследования - потому что тогда деструктор C вызывал бы только деструктор B. (Деструктор Б все равно будет называть А - и вы все еще катаетесь на тонком льду, потому что, если деструктор А бросает, вы идете прямо к terminate().)

0 голосов
/ 30 июня 2011

GCC 4.X является более строгим, чем предыдущие версии, и поэтому может не указывать его неявно. Попробуйте указать это явно.

Насколько я понимаю, если в классе B был деструктор, который явно ничего не бросал (т.е.

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

Все должно быть в порядке.

Несмотря на это, в прошлый раз, когда я проверял, было очень плохой практикой бросать исключения из д'торов.

Надеюсь, тебе это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...