The general consensus is that throw specifications are useless in C++. Most of the people who use them will only ever bother with the empty throw() clause and none others. And even then, it's usually only on functions where throwing an exception is genuinely dangerous, such as destructors, or member functions for exception objects.
The exception specification problem is a nasty one to solve. I've spent a lot of time thinking about proposals for how it could be solved. I even came up with an idea and suggested it to the C++ forum, which then received a lot of critical feedback. My current evaluation is that it's just not practical, at least not with what is known now.
What follows is a rather lengthy treatise on exception handling and specifications. If the subject bores you, feel free to ignore me.
I expect you're thinking along the lines of Java's checked exception specificiations, right? C++ adopted a somewhat different philosophy of exceptions from Java which makes specifications not work very well. In the Java method for dealing with exceptions, you need to know exactly what rare conditions might occur when your function is called, and either handle them all locally or declare them to be thrown from your function. From one point of view this makes sense. If your function might exit by throwing an exception rather than returning success, it would be nice for the caller to know this, and to know what types of failures might occur so it can plan for them. It ought to be at least part of the documentation, and preferably enforced by the language. So Java requires you to specify these things and checks your specification against your implementation. Certainly makes sense to me.
However, this has a few wrinkles in it. First of all, the exception checking mechanism is imperfect. It will generally spot unhandled exceptions, but it may have a tendency to spot exceptions that can't actually occur. For example, consider this:
#include <iostream>
class NegativeArgumentException { };
void pass_me_a_positive(double x) throw(NegativeArgumentException) {
if (x<0)
throw NegativeArgumentException();
// ...
}
int main() {
double x;
std::cin >> x;
x*=x;
pass_me_a_positive(x);
}
Under the Java philosophy, pass_me_a_positive() might throw NegativeArgumentException, so main() should be required to either catch such an exception or declare that it throws the exception. However, the programmer knows that the exception never will be thrown because the logic of the program won't allow for it. But the Java rules would still have him putting a dummy try{}catch(){} block in to appease the code analyzer.
Naturally, that's somewhat of a contrived example. But there are other issues. For example, consider polymorphism. Suppose you have a class something like this:
class FileError { };
class NetworkError { };
class Remote_Object {
public:
virtual std::string getvalue() const throw(FileError, NetworkError) =0;
};
where Remote_Object represents a handle of some sort for getting a value from some remote source. This remote source might represent a file on disk or a server somewhere on the network, so when you try to get the value, the file system might return an error, or a network error might happen, so you may be unable to retrieve the value. The code that actually
uses the class won't usually care
why there was a failure, though. Usually, the user of the class will want to just detect the exception and abort the current operation, passing the exception further out until the main() routine catches any uncaught exception, prints an error message, and quits or retries or does something else.
Now, though, suppose you want to create a new type of Remote_Object like this:
class UserGivenValue : public Remote_Object {
public:
class UserAbortedEntry { };
virtual std::string getvalue() const throw(UserAbortedEntry);
};
Unfortunately, under the Java model, this won't work, because a derived override is not allowed to throw any exceptions that the base function didn't declare. So, the writer of UserGivenValue can try to do a number of clunky things. He can translate the UserAbortredEntry object into a FileError object or a NetworkError object and throw that instead, but it's not really either of those types of errors. Or he can catch the UserAbortedEntry object and just ask the question over and over until the user condescends to give a value, but that's more like putting yourself in denial about the fact that the user didn't want to enter a value in the first place. Or he can modify the base class (and any functions that use the base class), but this only works if he is free to modify that code and results in a change of the class's specification, which could lead to problems with other applications using this class. And the tragedy is that the whole thing probably would have worked just fine if the language had allowed the UserAbortedEntry exception to be thrown in the first place since the user of the class usually doesn't care why the failure happened, only that it did, and the main routine is catching everything anyway.
This code example also wouldn't work under the C++ model of exception specifications, because it has a similar limit about allowing derived classes to throw exceptions that the base doesn't declare. In the C++ case, the author would have the option of throwing a UserAbortedEntry object anyway, but not declaring it. This is hardly better, since the result is a call to unhandled_exception() which usually calls terminate(). But in C++, the default exception specification is to allow anything to be thrown. So if all the exception specifications are simply removed, everything works fine again.
The C++ philosophy towards exceptions is that exceptions correspond to exceptional circumstances in execution. Therefore, code should usually be written with the common case of execution in mind, and enough exception handling code added in to properly handle the unusual circumstances, but no more than necessary for good recovery. If code is written this way, and then otherwise written so that operations in general may fail unless guaranteed not to, exceptions mostly stay out of the way. To that end, exception specifications are made optional and not checked. (Those two go together by the way, you can't make them checked without making them required. You can't check a function's exception spec without having the specs available for the functions it calls.) When you add exception specification code to all functions, you're one step closer to the old method of checking return values for error conditions.
That philosophy about exceptions also happens to be my philosophy, but if you don't agree with it, there's nothing wrong with that as long as you realize that is more or less why C++ is the way it is WRT exceptions.
Anyway, the bottom line is that a tool to actually check and formally verify C++ exception specifications would be quite a sophisticated project. Not impossible, but I doubt it's been done. And if it has, chances are it would occasionally warn about an exception that would never occur anyway. (Actually, probably more than occasionally, since C++ has exceptions for domain errors relating to improperly passed arguments.)
I guess the short answer is, no, there isn't a flag to allow g++ to check exception specs, and I doubt there's another program written currently that would do the job instead.
____________________________
I was charged with conspiracy to commit jay-walking, and accessory to changing lanes without signaling after the fact
![:blush :blush](emoticons/blush.gif)
.
++Adam H. Peterson