While not automated, you can make use of function-try-blocks, e.g.:
struct Example {
Example() = default;
~Example()
try {
// elease resources for this instance
} catch (...) {
// take care of what went wrong in the whole destructor call chain
}
};
-- https://cpp.godbolt.org/z/55oMarbqYNow with C++26 reflection, one could eventually generate such boilerplate.
What I’m thinking of is that the C++ exception runtime would attach exceptions from destructors to any in-flight exception, forming an exception tree, instead of calling std::terminate. (And also provide an API to access that tree.) C++ already has to handle a potentially unlimited amount of simultaneous in-flight exceptions (nested destructor calls), so from a resource perspective having such a tree isn’t a completely new quality. In case of resource exhaustion, the latest exception to be attached can be replaced by a statically allocated resources_exhausted exception. Callbacks like the old std::unexpected could be added to customize the behavior.
The mechanism in Java I was alluding to is really the Throwable::addSuppressed method; it isn’t tied to the use of a try-block. Since Java doesn’t have destructors, it’s just that the try-with-resources statement is the canonical example of taking advantage of that mechanism.