Ignoring for a moment that kernels generally disable destructors, and that "failed to clean up" is likely to leave your program in an unrecoverable state even without multiple exceptions being involved (think about what an exception means ... "failed to write to stderr" should not be an exception, and you should be doing little enough allocation during destruction that your dtor can manage even if out of memory) ...
Destructors throwing isn't broken, it just requires explicit care from the programmer to figure out which option to use in case of conflicting exceptions:
* If the existing unwind is a non-exception-unwind, there is no conflict. Exceptions thrown from a destructor just work™ and change it to an exception-unwind. Since C++11 you have to explicitly mark the dtor as `noexcept(false)` to indicate that you think you know what you are doing.
* If you're already winding due to an exception and want to preserve it, you can check for it at the start of the dtor, and wrap the dtor body in a try-catch which conditionally rethrows if there wasn't already one.
* If you're already unwinding due to an exception and want to ignore it in favor of the new exception ... doing this in C++ is pretty ugly but it's certainly possible. In order to use bare `throw` for the no-additional-exception case, you have to replace all stack variables with `option`-like wrappers so you can manually dispose them during `catch`. Other solutions exist if you don't care about correctly using bare `throw`.
* Or, you can do the safe thing and say "simultaneously unhandled exceptions means the programmer likely never considered how to handle this; give up"
Note that most languages that use `try-finally` have even bigger problems to deal with, since they have to worry about `return` as well as `throw`. Bugs and inconsistencies are frequent here.
`init_nfs_fs` doesn't "throw" from any of its destructors though - most destructors don't even want to throw. Note that all the functions called between the `out` labels don't have (or at least don't do anything with) a returned error value.
Destructors throwing isn't broken, it just requires explicit care from the programmer to figure out which option to use in case of conflicting exceptions:
* If the existing unwind is a non-exception-unwind, there is no conflict. Exceptions thrown from a destructor just work™ and change it to an exception-unwind. Since C++11 you have to explicitly mark the dtor as `noexcept(false)` to indicate that you think you know what you are doing.
* If you're already winding due to an exception and want to preserve it, you can check for it at the start of the dtor, and wrap the dtor body in a try-catch which conditionally rethrows if there wasn't already one.
* If you're already unwinding due to an exception and want to ignore it in favor of the new exception ... doing this in C++ is pretty ugly but it's certainly possible. In order to use bare `throw` for the no-additional-exception case, you have to replace all stack variables with `option`-like wrappers so you can manually dispose them during `catch`. Other solutions exist if you don't care about correctly using bare `throw`.
* Or, you can do the safe thing and say "simultaneously unhandled exceptions means the programmer likely never considered how to handle this; give up"
Note that most languages that use `try-finally` have even bigger problems to deal with, since they have to worry about `return` as well as `throw`. Bugs and inconsistencies are frequent here.