So, you pass file name to your data access library and the file is not there. How are you going to deal with it? Write an error to the log nobody reads and call terminate()? Create a new file and let users guess what happened to the data they expected? Or return an error code?
If you picked the last option (as most people do) - well, bingo, you've just put your error handling far from where the error occurred. The only difference with throwing an exception is that now every function up the call stack needs to check that error code till it reaches the place where you can handle it or, even more likely, till someone forgets to check or chooses to ignore it. Because, unlike Go or Rust, C++ compiler won't help you there.
Error codes don't undo I/O either.
As to "which functions can throw" - let me suggest a simple rule: every function can, unless you can prove otherwise.
Look, there are situations where it makes sense to avoid exceptions, but not for the reasons you listed. Exceptions are the least evil way to handle errors in C++. Google style guide bans them mostly for historical reasons, let's not cargo cult it.
Perhaps return an error code. Which the caller would check and deal with the error. (Besides, I'd be passing a stream object, not a filename.)
I/O is also network packets, graphics on the screen, motor movements.
> P.S. As to "which functions can throw" - let me suggest a simple rule: every function can, unless you can prove otherwise.
Exactly, that's the problem.
(1) There are clever hacks to mimic this behavior to some extent, but I don't even want to go there. If you really want this feature - just use a language that has it.
It would be great to have some function annotations to show which exceptions can be thrown, though. But still, keep in mind tha Google's style is pretty much equivalent to having a catch(...) after every call.
There was [0]. It is deprecated and generally discouraged, since it quickly becomes a maintenance nightmare (since you have to include unhandled exceptions for all functions called from that function, etc, all the way down).
The noexcept keyword was actually added to address some of the limitations.
Is there a better way to do it, maybe a static analyzer or IDE warning about possible exceptions?
Another way to express constraints are attributes, which static analyzers (and optimizers) also use. For example, GCC has a number of function attributes [2] to express invariants about code.
[1] http://clang-analyzer.llvm.org/scan-build.html#recommended_d...
[2] https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attribute...
Huh. I think Google C++ style guide makes a lot of sense. C++, the good parts.
What's wrong with the guide in your opinion?
I know a lot of people might disagree, but the common criticism of Google's C++ style, exceptions, tends to be a misfeature when you need to actually handle the errors.
It puts error handling code far from where errors occur, and where you often have the best chance to deal with it. It also obscures error sources, it's not immediately obvious in local method context just by looking at the source code which calls can throw and which not.
Exceptions also don't undo any I/O that was done, so things might be in pretty bad state -- and it tends to be pretty bad to deal with that a few method calls up.
I like errors to be on my face, even if they're "ugly". You tend to forget about hidden things.