| Program state is significantly more complex than just needing some RAII resources to cleanup via destructors. > during sections that may throw Yeah one of the problems with exceptions is it’s impossible to know what “may throw” other than “well I guess literally anything so everything”. It is very irritating. At the end of the day exceptions are just a little syntactic sugar. Or perhaps syntactic bitters. It is notable that systems languages designed after C++ all chose to not include exceptions. Go, Zig, Swift, Odin, Jai. Rust panics are kinda sorta exceptions in that they unwind. But their intended use case is for irrecoverable errors. And of course you can set panic=abort. C++ exceptions are very rarely treated as so serious module level irrecoverability. |
You're being rather vague. All throwing does is cause control flow to jump to the nearest catch that can handle the exception, destructing all objects along the way. I struggle to think of an example that could cause problems that isn't some variation of "I had some code after the exception that I needed to run, and it didn't run, because it wasn't set up to run at scope exit". I'd love to see such an example if you have one.
>it’s impossible to know what “may throw”
* If it's a throw statement, it may throw.
* If it's an expression that contains a 'new' operator, it may throw.
* If it's an expression that contains a dynamic_cast to a reference type, it may throw.
* If it calls a function that you don't know that it does not do any of the above, it may throw.
* If it's unknown if a function is called (e.g. types are templated), it may throw.
* Otherwise, it doesn't throw.
If you're managing resources manually, either make sure not to call any functions until you release them, or stop managing them manually. I encourage the latter.