- basic non-throwing initialization only constructor
- a "bool Initialize" method which does what the constructor would have done, but returns false on fail
- destructor as usual to clean up
But this is because I'm at Google where exceptions-are-no.Objects with an artificial invalid state are an antipattern in idiomatic c++.
And the destructor has to check for initialization before cleanup.
I'd be very suspicious of any failure avoidance system that relies on "user caution".
Now, true, some of these impose lesser burdens than others. Arguably, RAII imposes the least - but not zero. And if you forget with any resource, for that resource you are vulnerable.
And ultimately it should be possible to enforce that all resources are managed, because ultimately all resource interfaces have to be provided by the language runtime. To a certain extent enforcing user-defined invariants is always a matter of taste, but at the same time a language that makes it easy makes people a lot better at it.
std::ofstream file("example.txt");
if (!file.is_open()) return;
// ofstream will close in destructor.
And RAII doesn't even imply that the acquisition must happen via constructor. Edit: Technically it does, but the above pattern would not change if 'file' was a result of calling a free function or whatever.This is exactly not RAII. You acquired the resource and it might not be initialized. And it has the same problem: it's very easy to pass file around when it's not actually valid.
But full exception safety is obviously much more than just properly catching exceptions. I mean avoiding subtle traps like the ones here: https://herbsutter.com/gotw/_102/
Unless you have a bunch of code that just passes the object around without looking into it (so it won't fail there), and then when the crash finally happens, you have no idea where the invalid object came from.
This is really just another form of the billion dollar mistake, except you have invalid objects instead of null pointers (or in the worst case, you have both).
With an unhandled exception, you always have the context of where and why it happened (assuming you know the reason behind throwing it).
use abort() from stdlib.h