This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Why does debugging "pure virtual method called" have to be so hard?


>     Joe> I vote for throw __pure_virtual_exception;
>     Joe> where that class is derived from class std::exception.

Sorry I chose that phrase: I meant that I would have voted for something
like this in the standard.

Mark Mitchell points out:

>   class C {
>     virtual void f () throw () = 0;
>   };
> 
>   C& c = g();
>   c.f();

and the fact that the optimizer may wish to use the no-throw guarantee.

(The following is just a mental exercise; I'm not asking anyone to
do any actual work to implement it.  Think of it as food for thought).

Let's say that we were on the committee, and the proposal was that
pure_virtual_exception were to be thrown and this was your response.
It would seem, then, that in this case (the user has specified no
exceptions) the attempt to throw pure_virtual_exception would be bad,
so std::unexpected() should be called.  Since the compiler knows
that any call will be turned into a std::unexpected, it can wire
the vtbl entry for C::f directly to std::unexpected.

So, the change would be as follows: currently the vtbl gets a pointer to
__pure_virtual.  __pure_virtual would be changed to throw an exception.
At this stage, we've made no changes to the compiler itself, just to the
support library.

If, however, there is a throw specification like the above,
__pure_virtual_nothrow would be pointed to instead.  Now we've changed the
compiler.

What if we have something like
	virtual void f () throw (Foo, Bar) = 0;

There are always two possibilities: the specification allows
__pure_virtual_exception to pass, or it does not.  So the ideal compiler
would generate one of the two calls.  If we can't tell or we are lazy, it
would be better to make mistakes in favor of not throwing (so the
optimizer won't make bad code), so a simple thing would be to generate the
_nothrow version if there is any throw specification at all.

> I think calling terminate, abort, or some such is just fine.

Currently __pure_virtual is

void
__pure_virtual ()
{
#ifndef inhibit_libc
  write (2, MESSAGE, sizeof (MESSAGE) - 1);
#endif
  _exit (-1);
}

The _exit(-1) could be easily changed to abort(), and people debugging
the problem could still set a breakpoint on __pure_virtual.  Maybe that
one-line change is the one we should really make.



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]