20

For a library code, is it better practice to create and throw custom exception class (library::Exception), or just throw standard exceptions (runtime_error, invalid_argument, etc.)?

Daniel Langr
  • 22,196
  • 3
  • 50
  • 93
  • possible duplicate of [Should I inherit from std::exception?](http://stackoverflow.com/questions/1669514/should-i-inherit-from-stdexception) – timday Jan 20 '11 at 13:38
  • 1
    I don't think those questions are duplicates. One's asking about exceptions, and one about exception base classes. – David Thornley Jan 20 '11 at 21:07

4 Answers4

28

It's usually better to specialize (inherit) a standard exception and throw it.

This way it'll be possible to catch it as a generic exception just by catching a std::exception, but you could also catch specifically your custom exception type if you need more specialized code.

Also see this C++Faq about what to throw.

peoro
  • 25,562
  • 20
  • 98
  • 150
  • 4
    There's basically no better answer than this. Create your own custom exception classes which inherit from std::runtime_error (which already inherits from std::exception). That way your customers have the choice to catch your specific exceptions, or just catch std::exception or std::runtime_error. – Mephane Jan 20 '11 at 13:38
  • +1 This also has the added benefit of giving you the opportunity to add appendages to the exception being thrown. You can include more information such as the filename & line number of the code that generated the exception. See this for an example: http://stackoverflow.com/questions/4595350/c-declare-static-variable-in-function-argument-list-generate-keys-for-lines/4595976#4595976 – John Dibling Jan 20 '11 at 13:43
  • 1
    I'd say it depends on the situation. In the code base I maintain, there are very few errors you want to catch on a per-exception basis. Either you have one very specific exception to deal with, or you let them bubble up to the user interface. So there is no need in many cases for a very structured exception hierarchy, and standard classes (perhaps augmented with a few custom classes) do the job cleanly. Throw `std::invalid_argument` when argument is invalid, throw `logic_error` or `runtime_error` generically, and make custom exceptions for things like `bad_my_custom_dynamic_cast`. – Alexandre C. Jan 20 '11 at 13:46
  • @Alexandre C.: if you need an exception that has **exactly** the semantics of `std::logical_error` or `std::invalid_argument` that's fine: you could use that one. But if your semantics is (even slightly) different I think it'd be better to use a new exception type. It won't make any difference if the code that needs to catch the exception catches a generic exception (an `std::` one), but it will make a big difference if the code could need to be specialized for your exact exception. – peoro Jan 20 '11 at 13:50
  • I just understand that custom exception class allows user to filter all exceptions thrown by the library, and standrad exceptions allow user to distinguish the exception type (e.g. invalid argument). But I don't like the idea to create more custom exception classes to allow both. – Daniel Langr Jan 20 '11 at 13:54
  • @peoro: My point is that usually (from experience) you don't catch those `logical_error` or `runtime_error` exceptions except for providing a user message that something went wrong, because there is usually no way to recover (again, your situation may be different). So even the difference between the two is cosmetic. When you design exceptions which are meant to be caught early, custom hierarchies are useful, even if usually they consist in only a handful of classes. – Alexandre C. Jan 20 '11 at 13:54
8

Generally you should throw instances of classes in the stdexcept header or subclasses thereof. What class exactly makes sense depends on the specific problem. I think throwing instances of “category classes” std::logic_error and std::runtime_error is rarely useful since they carry no inherent meaning; they are used to distinguish the two main situations where exceptions can occur:

  • Subclasses of std::logic_error should be thrown by a function if it is called, but not all preconditions are fulfilled. The exception is the fault of the caller since it has failed to provide the necessary preconditions. For this category, you generally have to choose between throwing and undefined behavior; it is a trade-off between robustness and efficiently (e.g. std::vector::at() vs. std::vector::operator[]. These exceptions often cannot be handled; they are the result of bugs in the program.

  • Subclasses of std::runtime_error should be thrown by a function if all preconditions are met but the function cannot meet the postconditions or breaks invariants for reasons outside the control of the program (e.g., a file doesn’t exist, the network connection is lost, or not enough memory is available). These exceptions should usually be handled.

I think the available logic error classes (e.g. invalid_argument) are often good enough, because if they are raised, the code usually has to be fixed, and there is no reason for elaborate handling routines. On the other hand, the runtime error classes in the standard library are by their nature much less flexible and cover mainly the areas where the standard library itself has to throw exceptions. For your application, you should almost always inherit from these runtime error classes. For example, a class managing the operating system resource X should throw an X_creation_error which inherits from std::runtime_error if the constructor fails to allocate the resource.

Multiple virtual inheritance is often useful with exception classes. You can inherit from std::runtime_error or other stdexcept classes, from some “marker class” specific to your library, and from boost::exception to get the additional benefits of the Boost.Exception library. The Boost.Exception tutorial is highly recommended, especially Exception types as simple semantic tags and Using virtual inheritance in exception types.

Philipp
  • 48,066
  • 12
  • 84
  • 109
2

IMHO Custom exception. The customers of your library will apreciate this. He will know whats exactly raises the exception.

Víctor B.
  • 1,630
  • 2
  • 14
  • 21
2

From experience, it is rare that you need more than a very few exception classes.

In most of my code (mainly numerics -- if you do eg. IO, the situation is different), I throw standard exeptions (runtime_error, invalid_argument, ...) because they tend to indicate something that cannot be easily recovered from (except perhaps invalid_argument), and which will likely not be caught by user code (except perhaps at the top-level to throw a message box to the user).

If there is some exception which is intended to be caught by typical user code, eg. bad_custom_cast, or bad_market_data_identifier, instead of bubbling up to main (like a failure in a numerical routine, or bad_alloc), I make a custom class. But this is quite rare actually.

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197