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);
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();
and this means that SomeFunction
does not throw exceptions. Of course, a function can be declared without an exception specification:
void SomeFunction();
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);
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:

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