Reputation: 19123
I just saw this question and its related answers.
Considering I never ran into this way of using throw
s before, I was quite surprised to find out this is even possible.
Upvotes: 6
Views: 2443
Reputation: 2304
When the handler is entered, e will be a copy of the Int_overflow object that was created inside the add function to describe what went wrong. The parallel to function calls is now almost exact: The throw-expression passes an Int_overflow object to the handler declared to accept objects of class Int_overflow. The usual initialization semantics are used to pass this argument. The type of the object thrown is used to select the handler in approximately the way the arguments of a function call is used to select an overloaded function. Again, a slightly different way of looking at the throw-expression is as a return statement where the argument is not only passed back to the caller, but is also used to select which caller to return to.
[...]
Relying of such fundamental and well-supported language concepts rather than inventing some special ‘‘exception type’’ ensures that the full power of C++ is available for the definition and use of exceptions.
"Exception Handling for C++", Andrew Koenig, Bjarne Stroustrup, 1989
This may answer your question about the logic behind that behavior. The creators of C++ wanted to use pre-existing technology to implement the new feature.
For your question about legitimate use of that functionality I'll give you another quote from the same publication:
We do not wish to use exception handling as a substitute for more conventional control structures
I leave it to you and other commenters to decide if more modern practices may have surpassed the initial ideas of the inventors.
Upvotes: 3
Reputation: 3329
I'm not Bjarne Stroustrup, but I'll try to give an answer.
What's the logic behind allowing (almost) anything to be thrown and caught?
The convention is to throw a derivative of std::exception
from the standard library. If you limit what can be thrown, you're confined to using only that.
C++ tries to:
1. Give you a lot of flexibility
2. Manage the already complicated complexity of the language
By letting the language throw and catch anything, you're giving the programmer flexibility. You're also making the language less complex, by moving std::exception
to the standard library instead of it being part of the language itself.
Is there a use of the throw-catch syntax that goes beyond exception/error signaling?
Yes, you can use it for passing signals. It's an ill-advised anti-pattern (abuse).
Upvotes: 0
Reputation: 36379
C++ has a general philosophy of allowing the programmer to do whatever they like (and to shoot themselves in the foot), most restrictions are only in place to enable portability and even some of those aren't enforced by some compilers.
If you don't need (the admittedly small) overhead of creating a std::exception
object C++ doesn't force you to pay for it. For example you might throw an error code directly, this is much easier than creating a subclass of std::exception
with an error code member. Of course the caller of your code needs to know to expect to catch numbers not std::exception
subclasses. For this reason in general it's better to only throw subclasses of std::exception
but you don't have to.
Upvotes: 3
Reputation: 385104
This is hard to answer without speculation, but Bjarne's 1998 paper "An Overview of the C++ Programming Language" uses arbitrary types when describing exception handling, and suggests creating a hierarchy of said types for convenient/semantics. It would seem that he did not have a "base class" of exception
in mind for any of these in the beginning.
It's possible that the notion of having a standard hierarchy (based on std::exception
) began life as an "addition", a convenient way to approach Bjarne's suggested use of exceptions, rather than the building-blocks on which everyone's use of exceptions should be based. That contemporary practice is to derive all exceptions from std::exception
would seem to have come along later.
Nowadays, I can't think of a good reason not to do that, if for no other reason than people using your code will probably expect a top-level catch (const std::exception&)
to suck up anything useful. I do also tend to put a catch (...)
in main
, though, just in case.
Speaking more practically, if this weren't the case, there would have to be additional rules constraining throw
to only be "valid" on expressions with type deriving from std::exception
, which would not seem to have any real-world benefit sufficient to justify the additional rules. C++, believe it or not, comes from a place of minimalism in terms of the question "why don't we have such-and-such a rule", although obviously its bloat would seem to contradict this after all these years.
I doubt this has anything to do with using throw
for non-exceptional things, because that has always been considered bad practice. The way Bjarne describes this feature is:
Exceptions are used to transfer control from a place where an error is detected to some caller that hasexpressed interest in handling that kind of errors. Clearly, this is a mechanism that should be used only for errors that cannot be handled locally. [..] Exceptions can be used to make error handling more stylized and regular.
So it's clear that at least the original design intent (and, again, this is still common wisdom) is to use exceptions for exceptional/errory cases only.
Upvotes: 4
Reputation: 1429
1. You can throw anything because C++ does not define the purpose of specific classes as java or C# do. In this languages you can only throw objects of classes which inherit from their specified exception class. C++ does not have the one
exception class(nobody forces you to use std
-stuff).
2. Using throw/catch to signal non-error messages is called exception driven development and is indeed considered bad practice. exception driven development leads to code that's hard to understand. It also can result in sections of code not getting executed unintentionally. I highly recomment against doing this.
Upvotes: 3