tags:

views:

1693

answers:

4

It seems it is general accepted that exception specifications are not helping as much as one thinks. But I wonder if a specification which only uses std::exception might be a good compromise:

void someFunction()
    throw ( std::exception );
  • It documents the fact that this method/function might throw an exception.

  • It would make sure that only exceptions derived from std::exception are thrown and not some exotic classes like std::string or int.

So, would this be better then not having any specification at all?

Update:

Regarding the Runtime-Overhead: Think of it like the usage of asserts. You are using asserts regardless of the runtime-overhead, right? I know you usually can disable them for a release-build, so maybe a better approach would be to wrap the exception specification in a macro so you can disable it for a release build. Something like:

#ifdef DEBUG
    #define THROW( exception ) throw ( exception )
#else
    #define THROW( exception )
#endif

void someFunction()
    THROW( std::exception );
+1  A: 

On a conforming compiler, adding a non-empty exception specification generates the equivalent of a try/catch block around the function. Although it's possible to implement this in a way that has no run-time overhead, on some current compilers you do get an overhead.

So there may be a cost, and all you gain is that, if someFunction or something it calls raises on non-std::exception-derived exception, std::unexpected is called, rather than the unhandled exception mechanism.

So I guess my answer's 'No' :-)

James Hopkin
Adding a try/catch block has practically no cost (when there are no exceptions propagating) in modern compilers so that concern is a red-hearing.
Martin York
I'll change my wording - 'most current compilers' was not right. But if you're compiling for 32-bit using Visual Studio, it's still a consideration.
James Hopkin
Hmm, I've just noticed another answer saying that VC++ ignores exceptions specification entirely, and I think that might be right. Oh well ... they're still a bad idea :-)
James Hopkin
Actually, MSVC respects the nothrow one (or rather, uses it as an optimization hint), but it ignores all other specifications, and never ever calls std::unexpected.
jalf
+8  A: 

Yes but what do you expect to happen when something that is not derived from std::exception is thrown?

Would you like the application to terminate.
No stack unwinding not destructors being called to tidy up the code, just the application exiting.

The difference between Java and C++ exception specifications is that Java checks the specifications at compile-time. C++ on the other hand does all the checking at run-time. So by the time your specifications have been violated it is already too late.

Even in Java code there is a movement to stop to using them. What tends to happen there is at the start of the project the exception specifications are tightly defined. But as the code grows and becomes more complex the specifications are diluted to a more and more general form. This is because as the code grows more exceptions can be thrown and if they can not be handled immediately you need to modify the exception specifications of the whole call chain back to the point where they can be handled. (Note I am not a Java Expert but I do play in a mature Java code base).

The only exception specification (I think) that is worth much is the no throw specification. This does have a valid application (but you have to use it with the try/catch(...) block).

Also read Herb Sutters article:

And this thread on SO: http://stackoverflow.com/questions/88573/should-i-use-an-exception-specifier-in-c

Martin York
Nice explanation of the problems with compile-time-checked specifications. I've had that discussion a few times over the years ...
James Hopkin
@Martin York: Note that Herb Sutter's advice is to NOT even use empty exception specification. See http://www.gotw.ca/publications/mill22.htm
paercebal
+2  A: 

Exception specifications are essentially useless. Martin York already linked to Herb Sutter's post about them, but in short, you run up against the following problems:

  1. They're ignored by MSVC, and
  2. Their effect is nothing like in Java. The specifications are checked at runtime, causing a performance hit, witout giving you the compile-time validation you get in Java. All you're saying is "Insert extra code, such that when an exception is thrown, its type is inspected, and then either throw it as normal, or call unexpected() instead.

So all you're doing is making it harder to catch the exceptions that may be thrown, while at the same time slowing down your program. There really isn't much point.

jalf
The world does not revolve around MSVC ;-) and I don't see how it would be harder to catch the thrown exception, since the only thing it prevents is throwing some arbitrary, not std::exception based exception.
BugSlayer
READ Sutters post! They do NOT prevent arbitrary exceptions from being thrown. They only prevent arbitrary exceptions from being CAUGHT - a major difference.
MSalters
I did read the post. I can agree that strictly speaking they don't PREVENT arbitrary exceptions from being thrown. But since the program will abort (if you throw a different exception and if you didn't setup an error handler with set_unexpected) it is very similar to an assert.
BugSlayer
+1  A: 

I tipically would do this:

void someFunction() /* throw (std::exception) */;

The only effect of the throw statement in the function declaration is to modify its signature: a pointer to "void x()" and a pointer to "void x() throw y" are two different types.
In this way you are still documenting that the function might throw something, and you are losing nothing since the c++ compiler does not enforce any constraint anyway.

Paolo Tedesco