Confused about std::runtime_error vs. std::logic_error
I recently saw that the boost program_options library throws a logic_error
if the command-line input was un-parsable. That challenged my assumptions about logic_error
vs. runtime_error
.
I assumed that logic errors (logic_error
and its derived classes) were problems that resulted from internal failures to adhere to program invariants, often in the form of illegal arguments to internal API's. In that sense they are largely equivalent to ASSERT's, but meant to be used in release开发者_如何学JAVAd code (unlike ASSERT's which are not usually compiled into released code.) They are useful in situations where it is infeasible to integrate separate software components in debug/test builds or the consequences of a failure are such that it is important to give runtime feedback about the invalid invariant condition to the user.
Similarly, I thought that runtime_error
s resulted exclusively from runtime conditions outside of the control of the programmer: I/O errors, invalid user input, etc.
However, program_options is obviously heavily (primarily?) used as a means of parsing end-user input, so under my mental model it certainly should throw a runtime_error
in the case of bad input.
Where am I going wrong? Do you agree with the boost model of exception typing?
In this case, I think (at least for the most part) you're right and it's wrong. The standard describes logic_error
as:
The class logic_error defines the type of objects thrown as exceptions to report errors presumably detectable before the program executes, such as violations of logical preconditions or class invariants.
A command line argument that can't be parsed doesn't seem to fit that very well.
By contrast, it describes runtime_error
as:
The class runtime_error defines the type of objects thrown as exceptions to report errors presumably detectable only when the program executes.
That seems to be a better fit.
From a pure standard point of view, you are right. program_options should throw classes derived from either runtime_error
or logic_error
depending on whether the error is runtime or logical. (I did not review the current code to determine such idea classification for current exceptions).
From a practical standpoint, I have yet to see C++ code that makes useful decisions based on whether exception is logic_error
or runtime_error
. After all, the only reason you would throw a logic_error
as opposed to letting assert file is if you want to try recover somehow, and that's not different from recovery from a runtime error. Personally, I view logic_error
vs. runtime_error
the same way as checked exceptions in Java -- theoretically nice, but not useful in practice. Which means, that maybe, I'll just make program_options::error
derive from exception
. That is, when I'll find that 'spare time' everybody keeps talking about.
The current draft of the C++0x Standard says (clause 19.2):
1) In the error model reflected in these classes (i.e. the exception types), errors are divided into two broad categories: logic errors and runtime errors.
2) The distinguishing characteristic of logic errors is that they are due to errors in the internal logic of the program. In theory, they are preventable.
3) By contrast, runtime errors are due to events beyond the scope of the program. They cannot be easily predicted in advance.
Together with the quotes cited in one of the other answers this explains why Boost.ProgramOptions throws a std::logic_error for preventable errors caused by an 'error presumably detectable before the program executes'.
The user could verify that the file exists, run the program, and suddenly learn that the file has been deleted. That's why an I/O problem is always a runtime_error
. Stateful problems are runtime_errors, even if the caller could have checked, since another thread could cause the problem.
logic_error
is when the arguments to a function are wrong. It is only for things which could have been caught earlier with stronger type-checking.
So, "missing file" is a runtime_error
, but "improperly formatted filename" is a logic_error
.
Technically, a logical error within a function is a logic_error
too, but if you're smart enough to test for it inside your own function, you should be smart enough to prevent it in the first place.
IMO,
std::logic_error
is thrown by a user C++ program logic intentionally. Predicted by a user program.std::runtime_error
is thrown by a C++ runtime (or core part of the langauge…) to abstract lower level errors. Just happens without any intention without involving of any user code.
精彩评论