On 2012-05-09 12:25,
jens.m...@googlemail.com wrote:
> Derived exceptions are described very shortly in statements such as
> "The class invalid_argument defines the type of objects thrown as
> exceptions to report an invalid argument", which is kind of
> self-referencing. I am going to list some questions and
> interpretations in the following in the hope that some discussion
> could clarify things.
>
> 1. std::overflow_error and std::underflow_error
> These two are derived from std::runtime_error which is the base
> class for "events beyond the scope of the program". IMO, overflow
> and underflow are more logic errors in the program and not dependent
> on the runtime in general.
I think it's more natural to regard overflow and underflow as runtime
errors in general (especially in floating-point arithmetic); you try a
certain operation and then get the overflow/underflow status flags
during execution. Of course, you could try to avoid overflow/underflow
by checking the operands rigorously before the operation, but it often
gets too complicated and expensive. In addition, the standard library
throws overflow_error in bitset::to_ulong() or bitset::to_ullong() if
the integral value cannot be represented in the respective type, which
is clearly a runtime condition.
> 2. std::domain_error and std::invalid_argument
> We came up with a distinction saying that a domain_error is thrown
> when a value does not belong to the "static" domain of a function,
> e.g. a function that only works in positive numbers.
> std::invalid_argument should be thrown when a value cannot be used
> because the current state of the program permits that, e.g. putting
> a value twice into an object that holds unique values. This
> container could hold all values of a given type, e.g. string, but
> the domain changes when values are inserted.
It's hard to guess, but let's give it a try. The C++03 standard
library never uses domain_error, and the only occasion where
invalid_argument is used is when bitset constructor gets a string
portion that contains an invalid character (neither '0' nor '1'). I
would say the condition doesn't depend on the program state but is a
"static" domain violation (there's nothing dynamic in the set {'0',
'1'}), so the standard library's usage doesn't seems to agree with
your distinction. Furthermore, I would consider an error that depends
on the current program state as a runtime error.
You could say that an invalid argument is a domain error, or vice
versa. (You could say that an out-of-range argument is an invalid
argument, or it is a domain error, too.) The standard is really
underspecified here. Having said that, my guess is that domain_error
is for domain errors in a more mathematical sense, i.e. sqrt(x) or
log(x) for negative x, and invalid_argument for other more general
cases, e.g. a null pointer given to an argument required to be
non-null, an iterator pointing to a wrong container, an invalid second
argument to std::fopen, etc.
> 3. std::range_error
> I have no idea under what conditions a std:range_error should be
> thrown and not a domain_error, out_of_range_error, overflow_error,
> underflow_error. The only two functions throwing range_error are
> wstring_convert::from_bytes and wstring_convert::to_bytes, but I
> don't see why these two should not throw another exception.
They seem to be conversion errors, and curiously, other conversion
errors in the sto* family throw invalid_argument instead. I don't know
why.
> 4. std::out_of_range and std::length_error seem to be a special case
> of an invalid argument, so why is this not a subclass of
> std::invalid_argument?
I have no idea, either. Maybe the committee didn't want an exception
class hierarchy to be too deep.
> 5. std::regex_error
> This class is thrown when a string is not a valid regex, which is a
> domain error, but it is derived from std::runtime_error. It is also
> thrown when the state machine cannot be constructed due to illegal
> characters, which also seems more like a domain error than something
> outside the scope of the program.
I'm really curious here. What's the difference of constructing a
bitset with an invalid string and constructing a regex with an invalid
string? Why does one throw a logic_error and the other a
runtime_error?
> 6. std::bad_weak_ptr and std::bad_function_call
> These two class are directly derived from std::exception instead of
> std::logic_error. I think that is so because these present severe
> bugs in your program and not exceptions.
Maybe. Similarly for bad_exception, bad_cast, bad_typeid, etc, but I'm
not sure if they are necessarily severe bugs, nor if those under
logic_error are necessarily less severe.
--
Seungbeom Kim