I started thinking about this after reading this blog post by the creator of ZeroMQ.
A function or method should throw an exception under three circumstances:
- If there's something wrong with an input argument.
- If a required condition isn't met for running the function.
- An operating system error occurs, such as a failure to allocate memory, or to access a device or file. This is really a special case of #2.
Any other exceptions are the result of bugs in the function's implementation, and shouldn't be included in the documentation. For example, the function may call another function that throws an invalid_argument error. However, if the calling function has total control over the argument being passed, then that exception should never be raised.
Circumstance #3 could be re-phrased as a "system event", rather than a system error. For example, an exception could be thrown when a signal is received and handled by the process.