Click here to Skip to main content
Click here to Skip to main content

Standard Features Missing From VC++ 7.1. Part I: Exception Specifications

By , 7 Apr 2004
 

Introduction

ISO/IEC Standard 14882 "Programming Languages - C++" was adopted in 1998. However, the first C++ compiler (EDG) that fully adheres to the Standard appeared in late 2002, and as of this writing, there is only one compiler on the market that claims full ISO Standard compliance (Comeau 4.3.3 front end).

Until several years ago, it seemed that Microsoft was not very interested in making their C++ compiler Standard conformant. Then, with Visual C++ 7.1 (comes with Visual Studio 2003), Microsoft released one of the most Standard compliant C++ compilers on the market. It is usually claimed to have 98% Standard adherence.

The goal of this article series is to take a look at the "other 2%" - the standard features not supported by Microsoft Visual C++ 7.1. I will cover the three major missing features:

  • exception specifications;
  • export keyword;
  • two-phase name lookup.

Other than that, there are some other minor deviations from the Standard (maximum number of template parameters, etc.).

The first part will cover exception specifications. This feature seems to be implemented on some popular compilers (sometimes I use GCC 3.2 which supports it), and even MSVC++ 7.1 parses exception specifications and somewhat takes them into account.

Some Theory Behind Exception Specifications

The C++ Standard [1] allows adding a list of exceptions that can be thrown, to a function signature:

void SomeFunction() throw (E1, E2); // may throw E1 or E2

means that SomeFunction can throw only exceptions of type E1 and E2, including the types publicly derived from E1 and E2.

An exception specification may be empty:

void SomeFunction() throw(); // no exceptions thrown

and this means that SomeFunction does not throw exceptions. Of course, a function can be declared without an exception specification:

void SomeFunction(); // can throw anything

which implies that SomeFunction can throw any exception.

An exception specification is not considered part of a function type, and the Standard explicitly forbids that a typedef contains one [1] [2]:

typedef void (*pf)() throw(E1);      // compile error

Exception specifications are not checked at compile time - they are enforced at run time. If a function declared with a function specification tries to throw an exception not listed in its exception specification, a call to std::unexpected() will be made instead. Essentially,

void SomeFunction() throw (E1, E2)
  {
  ...
  }  

is equivalent to:

void SomeFunction()
try
  {
  ...
  }
catch (E1)
  {
  throw;
  }
catch (E2)
  {
  throw;
  }
catch (...)
  {
  std::unexpected();
  }

The default behavior of std::unexpected() is to call std::terminate(), which by default calls abort()[2]. However, if std::bad_exception is listed in the exception specification, std::unexpected() will throw an implementation-defined object of this class instead.

For better control over unhandled exceptions, it is possible to set a user-defined version of unexpected(), by calling function std::set_unexpected():

void MyUnexpected();
...
set_unexpected(MyUnexpected);

In this case, MyUnexpected() must obey some pretty rigid rules set by the Standard [1]. It cannot return - instead it can either call std::terminate() or throw an exception. If this new exception is not listed in the exception specification, a std::bad_exception will be thrown instead. If std::bad_exception is not among allowed exceptions in the exception specification, std::terminate() will be called. The following flowchart describes this logic:

unexpected handler flowchart

Exception Specifications in Practice

Fundamentally, specifying exceptions as a part of a function signature looks like a good idea. A function declaration is a contract between the implementer and the users of the function, and making exceptions a part of this contract means that a user has more information how the function will interact with his code. However, things are not that simple, and most of C++ community now believe exception specifications should be avoided altogether [3][4][5].

The major issue with exception specifications seems to be the fact that checking exception specifications is mostly a run-time mechanism. One of the best features of C++ is its strong static type system. If the compiler tells me that I screwed something up, it means my customers will never find out about it, because I will need to fix it before shipping my software to them. In this case, if I put an empty exception specification as a part of my function declaration, and an exception is thrown, it will not be the compiler that tells me something is wrong; my application will die - hopefully during a test cycle, but maybe after it has been delivered to customers [8]. GCC 3.2 didn't even issue a warning when I threw an unspecified exception from a function. The reasons for not making exception specifications compile-time checked are good [4], but they don't make this run-time checking any more appealing.

Somewhat ironically, Java designers took a different approach [6]. Instead of run-time enforced exception specifications, they introduced compile-time checked exceptions. A Java method declaration must list all the checked exceptions that can be thrown from the method in the throws clause. There are also unchecked exceptions (derived either from RuntimeException or Error class) and they are not checked by Java compiler. When I was learning Java several years ago, checked exceptions looked like a great feature to me. However, people who actually use Java for real-world projects seem to have a different opinion [7]. They see checked exceptions as a major hurdle that brings down the productivity while adding nothing to code quality. Many Java programmers use all sorts of tricks to circumvent compile-time exceptions checking.

As for C#, Andres Hejlsberg and his team decided to leave any kind of exception checking out of their language, at least for the moment [9] [10].

Visual C++ 7.1 and Exception Specifications

Microsoft Visual C++ 7.1 ignores exception specifications unless they are empty [11]. Empty exception specifications are equivalent to __declspec(nothrow), and they can help the compiler to reduce code size.

If you are tempted to use this feature to optimize your code, be aware: the compiler will not do any checking for you. If it sees an empty exception specification, it will assume you know what you are doing and optimize away the mechanics for dealing with exceptions. If your function throws anyway - well, shame on you. Use this feature only if you are 100% positive your function does not throw and never will.

Setting a non-empty exception specification results in a compile warning: warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow). Using non-empty exception specifications for documentation purposes only is not a good idea - it will work fine with VC 7.1, but one day when we move to a compiler that implements exception specification in a Standard conformant way, we may run into troubles.

Conclusion

Exception specifications are a way to enrich function declarations with information about exceptions they may throw. While the core idea sounds good, in practice, it turned out to be a failure - not only in C++ where exception specifications are enforced at run-time, but also in Java where they are checked at compile-time.

References

  1. ISO/IEC 14882 Programming languages - C++, 1998
  2. Bjarne Stroustrup, "The C++ Programming Language", 3rd edition, Addison-Wesley, 1997
  3. Herb Sutter: A Pragmatic Look at Exception Specifications, CUJ 20(7) 2002.
  4. Jack Reeves: "The (B)Leading Edge" Guidelines for Using Exception Specifications, 1996 The C++ Report April 15, 1996
  5. Boost Library Requirements and Guidelines: Exception-specification rationale
  6. Java Language Specifications: Chapter 11: Exceptions
  7. Bruce Eckel: Does Java need Checked Exceptions?
  8. Murphy Laws
  9. Bill Venners with Bruce Eckel: The trouble with Checked Exceptions - A Conversation with Anders Hejlsberg, Part II
  10. Anson Horton: Why doesn't C# have exception specifications?, MSDN
  11. C++ Language Reference: Exception Specifications, MSDN.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Nemanja Trifunovic
Software Developer (Senior) SAP
United States United States
Member
Born in Kragujevac, Serbia. Now lives in Boston area with his wife and daughters.
 
Wrote his first program at the age of 13 on a Sinclair Spectrum, became a professional software developer after he graduated.
 
Very passionate about programming and software development in general.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: I couldn't disagree more.memberNemanja Trifunovic13 Dec '05 - 1:49 
OK, so if I understand you well, you like exception specifications even if they are used only for documentation purpose. That's OK with me, but I will still disagree with some of your points Smile | :)
 

ProgramMax wrote:
Like I said before, if someone's code throws an exception not included in their specification, THEIR code is broken. That doesn't mean the concept of exception specification is broken. It is something they need to fix.

 
Their code is broken, so it is their fault, but your problem. If a function from a 3rd party library you use throws exceptions that are not included in the specification, you can be angry with them, but your schedules will suffer. In all fairness, sometimes it is all but impossible to track all possible exceptions that can be thrown from a function unless the compiler helps you with that, like in the case of Java. Not to mention generic libraries, where a user can use any type as a template argument and throw any exception at all.
 
ProgramMax wrote:
I think they are plenty-good for documentation. Any "troubles" you speak of are because the code is broken anyway, and needs fixed.

 
My point is that the behavior of the code will change once exception specifications are properly implemented with Microsoft compilers. With VC 7.1 any exception not listed in the specification will be propagated to the next level, and possibly handled somewhere. Now when we switch to a compiler that folows the standard in this regard, std::unespected will be called instead, and that's a scenario we were not able to test with VC 7.1.
 
I argue that doxygen-style comments are much better and safer way to document exceptions.
 
ProgramMax wrote:
And like I mentioned before VC7.1 doesn't ignore the specification (unless empty), it ignores the types.

 
But exception specifications are all about types. If it ignores types, what is left? Which part it does not ignore? Say we have a function:
 
void some_function() throw (E1, E2);
 
With VC++ 7.1 it is exactly equivalent to:
 
void some_function();
 
It is ignored the same way comments are ignored.
 
ProgramMax wrote:
Please don't take this offensively though

 
No offense taken. I like programming discussions Smile | :)
 


My programming blahblahblah blog. If you ever find anything useful here, please let me know to remove it.
GeneralOn your conclusionmemberMartin Friedrich15 Apr '04 - 1:05 
Hi, Nemanja!
 
While I consider most of your article quite interesting and insightfull, I cannot agree on your final conclusions.
I think, the main problem with exception specification do not stem from their existance per se, but rather from the way and, more important, the timing of their use.
 
Many people (including meSmile | :) ) tend to use exception specification in early stages during development phases - and this is why exceptions specifications proove to be such a pain in the arse in Java - and are thus constantly adapting their specifications when adding and removing exceptions.
But if exception specifications are introduced into the code towards the end of an development cycle after the code has stabilized, they don't do any harm. Instead, they become quite benign when it comes to automatic verification tools, because they unambigiously define the circumstances of function termination: by result, by allowed exception or by std::unexpected (C++ only). In a way, they can be used as a replacement for assertions, guaranteeing formal correctness of the program.
 
Bye,
Martin Friedrich

GeneralGood introduction of C++ Exception Specifications but ...sussRobert F8 Apr '04 - 22:20 
... totally wrong conclusion!!!
Exception Specifications are neither a failure in Java (Bruce Eckel is not representative for Java programming) nor in C++ (just because Microsoft ignores them).
Read the corresponding chapters in Stroustrup's "The C++ Programming Language"!
 
Best wishes,
R.F.

GeneralRe: Good introduction of C++ Exception Specifications but ...memberdog_spawn9 Apr '04 - 1:42 
Robert F wrote:
Exception Specifications are neither a failure in Java
 
Well said! They are a feature I find really useful that I miss in C++ (I use MSVC) and C#. But it's easy to see why 'must be caught or declared to be thrown' is not suited to the majority of programmers.
 
However, I also agree, otherwise a good article Smile | :)
GeneralRe: Good introduction of C++ Exception Specifications but ...memberemilio_g9 Apr '04 - 2:01 
Although I don’t completely agree with the article conclusion, I also don’t completely agree with this message. I mean: I found that a certain “level of truth” is in –fact– into Nemanja article.
 
One of the very first question I post to myself when starting analyzing something new or approaching a new problem or technology – may looks strange – it is not “Is it standard” or “How many will agree”, but it is “Does it work” and then “Is it useful” (and the consequence id “to do what”)
 
Now, Whatever can Mr Eckel or myself be representative in the C++ or Java community, I found to be a matter of fact that exceptions – even if introduced with all the good intentions – too much often become a nightmare to be used.
 
As a result ... the most of them are never caught nor declared to be thrown. And many of them seems to be declared just to say “don’t you try to make me throw that !”.
How many of you, not inside a specific library, but in an application code, check ALWAYS for a new returning NULL ?
How many function throw, leaving inconsistent state or unrecoverable dirty heap ?
 
There is something strange in the exception world:
If who wrote the function thrown an exception outside, it means he had encountered a problem he couldn’t solve. How many chances do I have to solve it ? If I asked for a new object it means I need it. How can I do without ? If the answers is (as in the most of the case, really is) I cannot, I’m forced to throw again. And who called me ... again. And again !
 
As a result, the most of the exceptions cannot be anything else than ... abnormal program terminations.
 
Of course: to have them is better than don't have them. But very little better
GeneralRe: Good introduction of C++ Exception Specifications but ...memberMattyT13 Apr '04 - 22:25 
I certainly don't check that new returns NULL - but if I want to know if new fails I do catch bad_alloc...I'm sure that's what you meant? Wink | ;)
 
As for exception specifications, typically I haven't found them useful though there are exceptions - pun intended Wink | ;) . Particularly with no-throw clauses. But I tend to agree with the author - that they're a failure - because it's rare that you can use them and get expected results in a compiler and platform independent manner.
 
Mind you, exceptions themselves I've found very useful and crucial to software development in C++.
 
A good article - I'm looking forward to the covering of export... Smile | :)
 
Cheers,
Matt
GeneralRe: Good introduction of C++ Exception Specifications but ...memberemilio_g13 Apr '04 - 22:53 
MattyT wrote:
if I want to know if new fails I do catch bad_alloc...I'm sure that's what you meant?
 
Yes ... but the point is another: whatever is the method you use to discover that new has failed ... what do you do after ?
 
In the most critical cases, I found that who catches the exception has very few chances to correct the problem. Also because the "problem" is not always originated by the caller (bad parameters or whatever), but from something alien (the availability of a block of memory at a given moment) to the programmers of both the caller and the called.
 
The only thing they both can do is ... note that it happens. But none of them can really continue the operation in a safe way. Hence the program is (sooner or later) terminated. No other chance.
 

GeneralRe: Good introduction of C++ Exception Specifications but ...memberperlmunger14 Apr '04 - 4:51 
Here's what the creator of C# has to say about it:
 
"Anders Hejlsberg: Yeah, well, Einstein said that, "Do the simplest thing possible, but no simpler." The concern I have about checked exceptions is the handcuffs they put on programmers. You see programmers picking up new APIs that have all these throws clauses, and then you see how convoluted their code gets, and you realize the checked exceptions aren't helping them any. It is sort of these dictatorial API designers telling you how to do your exception handling. They should not be doing that."
 
The whole interview with Bruce Eckel: http://www.artima.com/intv/handcuffs.html
 
-Matt
 
------------------------------------------
 
The 3 great virtues of a programmer:
Laziness, Impatience, and Hubris.
--Larry Wall
GeneralRe: Good introduction of C++ Exception Specifications but ...memberMattyT14 Apr '04 - 16:48 
I agree that often you can't do a great deal if new fails. Allowing the exception to remain uncaught - and having your program terminate - can be a valid response.
 
However, I can also think of many situations where there are different ways to handle new throwing. Consider where the user may attempt to create 'x things' and halfway through trying to create them new throws an exception. A valid response in this case would be to delete everything that was created succesfully and inform the user that they cannot create that many things - try less or free up memory.
 
To my mind the exception system is perfectly suited to this task.
 
And if you're doing really critical things then you shouldn't be using dynamically allocated objects...
 
Cheers,
Matt
 

GeneralRe: Good introduction of C++ Exception Specifications but ...memberemilio_g14 Apr '04 - 19:43 

MattyT wrote:
To my mind the exception system is perfectly suited to this task.
 
You're right. But the problem was not "use or not exceptions" but "use or not checked exceptions"
And their use force you to redeclare all the exception that can be thrown inside your code and that your code wouldn't cath in theat same function.
 
MattyT wrote:
And if you're doing really critical things then you shouldn't be using dynamically allocated objects
 
Unsure | :~ Depends on the "things". If objects are polymorphic and their type can be known only at runtime (because it depends on some user selection) there is almost no other choice than dynamic object into a collection (STL collections use dynamic memory ...) of std::auto_ptr or even more sophisticated smart pointers... probably to an abstract base, or even interface!
 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 8 Apr 2004
Article Copyright 2004 by Nemanja Trifunovic
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid