Exception policy for "finally" in C++

168 Views Asked by At

Consider the class finally, running arbitrary user code in destructor.

Here's the most minimal implementation (without forwarding, auxiliary function, etc.):

template<typename Func>
class finally
{
public:
    finally(Func f) : f_(f) {}
    ~finally() { f_(); }

private:
    Func f_;
};

The question is: how exceptions in user code should be treated? .

Here are the variants I could think of, which of them do you think is better, assuming the class is supposed to be used in broad range of situations?

1) Do nothing. ~finally() /*noexcept*/ { f_(); }

Destructor of finally is implicitly noexcept, so any exception in user code leads to terminate(). User must think every time about noexceptness of his code and guard it manually with try/catch if it throws.

2) Completely transparent destructor. ~finally() noexcept(f_()) { f_(); }

Destructor of finally is conditionally noexcept, so any exception is passed through and terminate() is called only if it happens during stack unwinding. User should probably think about stack unwinding scenarios, but calling terminate() in such situations may be the right decision by default.

3) Catch all exceptions in destructor. ~finally() { try { f_(); } catch (...) {} }

Classic destructor not throwing anything. Restricts user's capabilities of error checking with exceptions, but with good intend. Probably less efficient because of try/catch block. User doesn't have to think about anything.

3+) (Probably) optimized 3), uses specialization/SFINAE to omit try/catch block if f_() is noexcept.

May redundantly enclose C functions like fclose(FILE*) in try/catch block since they are not noexcept, but such functions are probably not used with finally directly, but through lambdas, which also can be easily not marked as noexcept out of forgetfulness.

4) Static assertion that f_() is noexcept.

The user have to explicitly mark his code as noexcept every time, then catching or not catching exceptions is his concern. Again restricts user's capabilities of error checking with exceptions, but with good intend.

4+) 4) plus some specialization of finally (maybe even another separate class template) with semantics of 2) which is free of the assertion, but must be used explicitly.

0

There are 0 best solutions below