Either implicitly detaching or joining a joinable() thread in its
destructor can result in difficult to debug correctness (for detach) or performance
(for join) bugs encountered only when an exception is thrown.
These bugs can be avoided by ensuring that
the destructor is never executed while the thread is still joinable.