MBZ
MBZ

Reputation: 27592

throw non-exception objects

C++ allows throwing any kind of objects. From exceptions to string and even int. But I've never seen any real world application of throwing anything other than exceptions.

My question is, what is the application for throwing non-exception objects?

Upvotes: 15

Views: 4363

Answers (7)

Victor Mataré
Victor Mataré

Reputation: 2671

I do not agree with the general notion that only derivatives of std::exception should be thrown. Of course I can agree that throwing objects with complex data or behaviour can be very problematic and should only be done with great care.

However that neither implies any restriction on the inheritance hierarchy of the thrown type, nor on the way (or the reasons why) stack unwinding is employed by your application. And the throw operation is just that: a clean and well-defined way of unwinding the stack up to a defined point (the matching catch) without having to involve explicit handlers in the intermediate frames.

And of course there are legitimate use cases for throwing that do not imply that an error or anything exception-al is happening. Think for example of a simple language interpreter, where the host language stack corresponds to the guest language stack. To implement interleaved parallelism in the guest language, stack unwinding is exactly what you need to do when a guest operation blocks (or yields). You want to unwind up to the starting point of the parallelism and try the next of the parallel branches. That situation is neither exceptional nor an error of any kind.

Observe that the keywords are called throw/catch and that the exception concept is not baked into the language in any way. This is (one of) the reason(s) for that.

Upvotes: 0

Nikos Athanasiou
Nikos Athanasiou

Reputation: 31519

More of a hack rather than a language feature, you could throw an object and then catch it to force a function to "return" something different than its normal return type.

int aFunc()
{
    throw foo(); // if you catch that foo, you 've imitated returning foo
    return 0; // ok just an int
}

This would ofcourse be a terrible design choice and a violation of type safety offered by C++ but say you have a function heavily used in a huge code base and you want to try some change (which involves altering the return type) then that would be dirty way of trying something out before actually implementing the change (and grep the whole code base to do changes)

EDIT:

You should read the post more carefully. I 've said "a terrible design choice" and "a violation of type safety offered by C++" and "before actually implementing the change". If that is not enough of a warning I don't think those comments or downvotes would be.

On the other hand try altering the return type of a function used 666 times in a code base of 6e06 lines to find out that it's not what you want after you've uploaded it on your version control system and broke the compile multiple times for developers working on other plattforms than you.

If there was a shortcut wouldn't you want to know about it? Wouldn't you use it until implementing the change and actually posting it to your code base?

Even if the answer to those questions is "NO" I thought this post was about exploring possibilities, and just mentioning one is not per se 'evil'. I personally heard this one from a Bjarne's talk http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style who afterwards said the same things about not using such things.

Upvotes: 6

James Kanze
James Kanze

Reputation: 153919

In general, any object which is thrown should derive from std::exception. There are exceptions, however. The most obvious: I've worked on projects which preferred throwing an int to calling exit(). Of course, this only works if main follows the convention of catching int and returning it. (The advantage of this is that all local variables will be destructed, where as they won't if you call exit().)

And in small throw-away test programs, I'll often just throw a string literal (which can be caught with char const*), which can be immediately output. (This is not a good solution for any production code, but when you're experimenting in order to learn something, it seems acceptable.)

Upvotes: 2

AnT stands with Russia
AnT stands with Russia

Reputation: 320531

I'm not sure what prompted the question, since you are free to choose the "application" in such cases as you see fit.

The purpose of an exception of object is to indicate the fact that an exception occurred and, usually, to carry some exception-specific information with it from the thrower to the handler. If some type is sufficient for that purpose in your application, then you can use that type as "exception" type. You can throw int values, std::string values and anything else, if you want. It is entirely up to you.

If all you want to carry from the thrower to the handler is an int value, then type int will serve that purpose as an "exception" type. That's all there is to it.

C++ does not impose any specific requirements on the types you can throw. For this reason, there is really no such thing as "exception" type or "non-exception" type. What is "exception type" and what is not is determined by you and only by you in your code. You can throw anything, as long as you know how to catch it and how to interpret what you caught.

The first benefit of using class types to represent exceptions is that class types are freely user-definable, i.e. you can easily define as many exception types as you want. Then you can use many independent, non-interfering exception "flows" that throw and catch only exceptions of their respective types.

The second benefit of using class types to represent exceptions is that class types are easily extensible. I.e. at any moment you can add an additional "payload" information to your exception type, and that payload will be carried from the point where the exception was thrown to the point where it is caught and handled.

If you are not interested in any of these benefits, you can simply throw and catch values of type int to represent your exceptions. This will work. But I'm almost sure you will quickly run into the limitations of this approach with regard to both maintenance and extensibility.

Upvotes: 1

John Dibling
John Dibling

Reputation: 101456

From a viewpoint of practicality, there is almost1 no application for throwing strings, ints, or anything else that isn't derived from std::exception.

This isn't because there's no indication for doing so, but because there are contra-indications that suggest why you shouldn't.

There are two main reasons why you wouldn't want to throw anything that's not derived from std::exception:

  1. Exception safety. If you throw, for example, a std::string and the construction or copy of that string raises another exception, terminate will be called and your process will cease to exist. You'll never get a chance to catch that std::string.
  2. Usability. Throwing derivitaves of std::exception makes it possible to catch (const std::exception&) in a generic fashion. If you throw something else, you will need a catch for that case.

A good discussion of exceptions can be found here.


1 Almost no application [...]: There are exclusions to every rule, but even in acknowledging this, I have never seen a legitimate exclusion to throwing a derivitave of std::exception.

Upvotes: 13

bobah
bobah

Reputation: 18864

As @galop1n answered, you can throw anything you like. But

  1. Usually they throw plain data objects rather than pointers to make sure compiler can automatically manage memory so throw(type()) ---> catch(type const& e) as a result
  2. Usually they throw something inherited from std::exception to meet expectation of those hoping to be catching everything loggable with catch(std::exception const& e). Though you may contradict that they should not be catching anything that they are not aware of what it is.

Upvotes: 0

galop1n
galop1n

Reputation: 8824

You throw whatever you wants, it will always be an exception as you throw it. The standard library use classes inherited from std::exception and this is a design choice.

If you feel like throwing an enumeration is enough for needs, as an example, why enforce you to throw an object…

Upvotes: 0

Related Questions