8
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;
}

That code gives the following error:

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

on my debian testing ( gcc (Debian 4.6.0-10) 4.6.1 20110526 (prerelease) ) but compiles without errors on previous gcc versions ( 4.5 on my debian system again).

How does an exception specification affect virtual destructor overriding? According to that answer the compiler is supposed to create a default constructor matching the throw declaration of the base class. Obviously this is not what happens on new gcc. What has changed, what is the correct compiler behavior and is there some easy solution to the problem other than manually adding empty destructors in derived classes ( compiler flag for example).

Community
  • 1
  • 1
Yordan Pavlov
  • 1,303
  • 2
  • 13
  • 26
  • Is that the actual code? If you skipped a member declaration, that can change the result. Also, did you specify C++11 support? The rules have changed slightly wrt destructors and while the code should still be fine there might be an error somewhere there. – Dennis Zickefoose Jun 30 '11 at 18:47
  • 4
    No, that is not the actual code. I can tell because it has at least one syntax error. @Yordan, please post actual, compilable code when asking a question. For details on how to do that, and why it is important, see http://sscce.org. – Robᵩ Jun 30 '11 at 19:16
  • 1
    @Rob - O.o You've got to be kidding..? It's not a question with some complicated and long source code, where such things are important. Two obvious semicolons are missing, this doesn't change the question, the information, the environment, anything. – Kiril Kirov Jun 30 '11 at 21:28
  • 1
    @Kiril: I agree 100% with Rob. If an OP introduces new errors into the posted code, how can we be expected to find the error in the original code? – TonyK Jun 30 '11 at 21:50
  • In this case a complete, compilable example is doubly important because if he added a member to the derived class that he removed for simplicity, whether or not the error is his fault or the compiler's can change. As it stands, that error is a compiler bug. – Dennis Zickefoose Jul 01 '11 at 04:50
  • @Rob, @Dennis, @TonyK, OK I take some stick for the not working example. Trying to provide a real illustrating one, it turned out that the scenario is a bit more complicated. Please have a look. – Yordan Pavlov Jul 01 '11 at 11:46

2 Answers2

3

I presume that in the real code either ~A() or ~B() is declared virtual? (The error message is complaining about a virtual destructor, but in the code as written none of the destructors are virtual.)

I believe the virtual inheritance is what is triggering your problem. C's (implicitly defined) destructor is required to first call ~B() and then, because C is the most-derived class, to call ~A(). (12.4/6)

The generated exception specification for ~C() is required to allow any exception to propagate, because it directly calls ~A() which has no exception specification. (15.4/13)

And that then triggers your error - you can't override a virtual function with a throw() specification (B's destructor) with a version that may throw. (15.4/3)

The solution would be to put throw() on A's destructor. (If you can't do that, then why are you doing it on B's?)

The error also wouldn't happen without the virtual inheritance - because then C's destructor would only call B's destructor. (B's destructor would still call A's - and you're still skating on thin ice, because if A's destructor throws you're going straight to terminate().)

Alan Stokes
  • 18,815
  • 3
  • 45
  • 64
  • Thank you for the answer! You were right about A having a virtual desctructor which I have missed ( I corrected this in the example now). Looks like out of the solutions you offer, adding throw() to A is the right one for my case. – Yordan Pavlov Aug 26 '11 at 12:27
  • A better solution is to not use a `throw` specification at all. This specification is now widely viewed as a mistake in the language. – David Hammen Aug 26 '11 at 13:34
0

GCC 4.X is stricter than previous versions, and therefore may not state it implicitly. Try stating it explicitly.

The way I understand it, if class B had a destructor which explicitly threw nothing (ie.

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

It should be ok.

Regardless, last time I checked it was very poor practice to throw exceptions from d'tors.

Hope that helps ya some!

Syndacate
  • 637
  • 1
  • 7
  • 15
  • It was a poor practice to declare exception specifications as well – BЈовић Jun 30 '11 at 19:41
  • "is there some easy solution to the problem **other than manually adding empty destructors in derived classes**". Also adding `throw()` (note - it's _empty_ throw specifier (something like the `nothrow` in C++0x) ) in destructors is different than just using throw specifiers. It's not a bad practice. It's even recommended - destructors _should_ not throw, right? (: – Kiril Kirov Jun 30 '11 at 21:19
  • I'm not sure if it is possible or not..but things shouldn't be thrown out of d'tors, as far as I know. That means you have to wrap every time you delete an object in a try/catch. I would say: No - but this looks like abusing the throw mechanism to me, so I can't say for sure what happens when you abuse it one way opposed to another. Though no, after reading the excerpt from the OP's post from the C++ spec, there is no way to do it without specifying the same exception types as the base class's overridden function. I assume this has to do with the pointer type ambiguity. – Syndacate Jul 27 '11 at 00:39