> By design exception handlers are handlers of exceptional events, which due to their exceptional nature either lead to a controlled recovery or controlled exit.
Exceptions are commonly used for events that are not really exceptional. In Java there is a precise distinction about them (checked vs unchecked exceptions), in C++ not.
Commonly libraries (not the C++ stl to be fair that rarely uses exceptions) use exception for things that are expected during a program execution: a file does not exist, a network socket closes, a resource is not available, the user interrupts the program, etc.
You may say: well, you should use exceptions for the first kind of error handling and error codes for the second, problem is that adds even more confusion, since you have some error conditions that may throw an exception and some other that may return an error code!
The simple solution is to not use exceptions at all, and the best way to do so is to use a language that doesn't have exceptions (such as C, but also Go, Rust, Zig, in general the trend for new languages seems to be to not have exceptions, and probably there is a good reason behind). While most C++ compilers let you can disable exceptions, but that will turn any throw of an exception into a panic or worse undefined behavior for code that uses them.
Especially in C++ exceptions are even implemented in a way that makes them more dangerous to use compared to other languages (such as Java):
- there is no indication about the fact that a method may throw an exception, rather there is the key noexcept that signal the contrary (that is all methods may throw exception except the one marked with noexcept, and there is no way to know which kind of exceptions a method may throw)
- you are not forced to handle exceptions (in Java for checked exceptions you either handle them locally or have to declare in the signature of the method that it may throw exception)
- exception introduce an hidden flow of control that may create various bugs impossible to spot (especially if this hidden flow of control passes trough libraries that you don't know what they do, and may for example have allocated resources that are not freed during the stack unwinding).
Having exceptions in low-level languages to me is a bad idea. Having them in higher level languages it's less of a bad idea because you have other form of protections, but still you can avoid them even there (I tend to not use exceptions in TypeScript, and prefer to return a Result type, and wrap any standard library function that may throw exception in this)
Exceptions are commonly used for events that are not really exceptional. In Java there is a precise distinction about them (checked vs unchecked exceptions), in C++ not.
Commonly libraries (not the C++ stl to be fair that rarely uses exceptions) use exception for things that are expected during a program execution: a file does not exist, a network socket closes, a resource is not available, the user interrupts the program, etc.
You may say: well, you should use exceptions for the first kind of error handling and error codes for the second, problem is that adds even more confusion, since you have some error conditions that may throw an exception and some other that may return an error code!
The simple solution is to not use exceptions at all, and the best way to do so is to use a language that doesn't have exceptions (such as C, but also Go, Rust, Zig, in general the trend for new languages seems to be to not have exceptions, and probably there is a good reason behind). While most C++ compilers let you can disable exceptions, but that will turn any throw of an exception into a panic or worse undefined behavior for code that uses them.
Especially in C++ exceptions are even implemented in a way that makes them more dangerous to use compared to other languages (such as Java):
- there is no indication about the fact that a method may throw an exception, rather there is the key noexcept that signal the contrary (that is all methods may throw exception except the one marked with noexcept, and there is no way to know which kind of exceptions a method may throw) - you are not forced to handle exceptions (in Java for checked exceptions you either handle them locally or have to declare in the signature of the method that it may throw exception) - exception introduce an hidden flow of control that may create various bugs impossible to spot (especially if this hidden flow of control passes trough libraries that you don't know what they do, and may for example have allocated resources that are not freed during the stack unwinding).
Having exceptions in low-level languages to me is a bad idea. Having them in higher level languages it's less of a bad idea because you have other form of protections, but still you can avoid them even there (I tend to not use exceptions in TypeScript, and prefer to return a Result type, and wrap any standard library function that may throw exception in this)