16

I am writing some library functions that needs to do some error reporting. I want to use exceptions rather than return values.

I wrote my functions that throws int exceptions.

Eg:

if(strm->atEnd()){
    // unexpected end of stream
    throw -2;
}

My question is, is this method OK? Or should I throw a exception derived from std::exception?

In what way is throwing a std::exception better? (Other than being able to use catch(std::exception &e))

Is throwing int exceptions bad practice? (all throw int values are documented in doxygen comments)

I can't find any reason as to why (in this case) should I throw an object.

Alex Kulinkovich
  • 4,408
  • 15
  • 46
  • 50
RushK
  • 525
  • 1
  • 5
  • 13
  • 2
    I may do that when I am hacking stuff together. But when I am finished it will always generate a real exception object (derived from std::rtuntime_error). As this simplifies all my exception handling code. Say you catch that in main(). How do you know which component generated error -345678? – Martin York Aug 08 '11 at 00:04

5 Answers5

19

I would throw an exception based on std::exception.

throw std::runtime_error("unexpected end of stream")

I find this easier to catch, log, et cetera. It also allows the removal of a comment and a magic number from the code.

This message can then be sent to the end-user to give them a hope of fixing the problem.

Users and library consumers can't read the comments in code, and they are unlikely to know what '-2' means.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
9

Exception are for exceptional behaviour. They're the last thing that you should worry about optimizing!

Donald Knuth said:

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil

Also, an object as exception may carry information about the error.

For example, you have an exception that means that a file cannot be read. If you throw an object exception, the object may carry the file name, which you cannot have with ints.

If the exception origin is unknown (deep in your stack) and no one catches it, it will be easier to debug the program if the exception is an object with proper information.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
André Puel
  • 8,741
  • 9
  • 52
  • 83
7

My question is, is this method OK?

Think about the readability. Wouldn't

throw CUnexpectedEndOfStream();

be more readable than

throw -2

?

And in a lot of cases wouldn't seeing an instance of CUnexpectedEndOfStream thrown in the debugger mean TONS more than -2. That's not to mention that CUnexpectedEndOfStream could store gobs of useful information about the problem such as say the file that couldn't be read and maybe more info on the nature of the problem.

Or should I throw a exception derived from std::exception?

Inheriting from std::exception may be helpful if that's how you choose to organize your other exceptions. It a convenient base class that client code can use. Also depending on the exception you may want to use std::runtime_error.

Is throwing int exceptions bad practice? (all throw int values are documented in doxygen comments)

Who said it was bad practice? Throwing exceptions is a great way to handle exceptional situations. Most of the exceptions I throw are because of something that could have been prevented by the client code doing what it was supposed to-- the user of my code violated the contract. But many other exceptional non-normal cases also exist like OS errors, disks filling up, etc. All the things that aren't part of your programs normal flow. More importantly, since they're not part of your program's normal flow, you don't need to worry about performance.

As an example, I once used exceptions to trigger that a certain message parsing failure occurred. However, I found that these parsing errors occurred frequently to the point where I started handling exceptions and fixing the problem input and reparsing. After a while, I realized that a more readable solution would be to fix the problem directly in the parsing code and stop treating it like an exceptional case. All the code that made parsing decisions was put back in one place and I wasn't throwing exceptions like a drunken sailor throws out curse words.

Doug T.
  • 64,223
  • 27
  • 138
  • 202
3

You should throw an exception derived from std::exception, e.g. std::runtime_error.

Most existing code assumes that an ordinary C++ exception is a std::exception, and anything else is a "hard exception" to be propagated up to a very high control level, like main.

For example, existing code will most probably not be able to log any reasonable message for your int. It will just be "unknown exception type".

Cheers & hth.,

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
0

Why don't you do this:

if(strm->atEnd()){
    // unexpected end of stream
    throw std::exception("-2");
}

throw -2 is bad because the type of -2 is neither std::exception nor derives from std::exception.

Or you should better write your own class as:

class FileException : public std::exception
{
      //...
};

And then

 throw FileException("Unexpected end of stream");

which is more readable.

bergercookie
  • 2,542
  • 1
  • 30
  • 38
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 5
    Personally I have stopped deriving my own exception classes (I just use std::runtime_error); Unless there is specific situation that I can catch and correct for with the specialized exception. If all I can do is log then std::runtime_error is usually the perfect choice. Note: FileException should probably derive from std::runtime_error (as std::exception does not have a constructor that takes an error message) sub note: MS has an non standard extension to std::exception that allows you to pass an error message. – Martin York Aug 08 '11 at 00:09
  • 1
    Why on earth would you keep the "-2" but put it as the exception reason? – Lightness Races in Orbit May 22 '14 at 18:51
  • @LightnessRacesinOrbit: I don't care about the "value". In this answer, all I cared for is the "type" ..i.e `throw "Unexpected end of stream"` is still bad. So throw exceptions of type which directly or indirectly derives from `std::exception`. – Nawaz May 22 '14 at 19:00