clean way to run modern C++ code at function exit if it may throw
20:24 21 Dec 2025

I'm writing a Windows service in C++ (Visual Studio 2022, C++20), and the service was unexpectedly terminating in the field. It was related to an update I made long after writing the original code, where an inner function f needed a flag set for the duration of its execution, and then returned to unset at function exit. To make this change I just added a couple of lines of code, as shown below - the SetFlag(true) and scope_guard:

void outer() {
    while(true) {
        try {
            many_nested_functions_leading_to_f();
        }
        catch (const MyException&) {
            /* handle exception and then retry with the outer while loop */
        }   
    }
}


void SetFlag(bool) {
    /* can throw MyException */
}


void f() {
    /* We need flag to be true for the duration of this function */
    SetFlag(true);
    auto guardClearFlag = sg::make_scope_guard([] { SetFlag(false); });

    /* complicated flow control, many return paths .. */
}

SetFlag is designed to throw on error, and in that case I want execution to resume way up the call stack at an outer function, where I clean up and then retry by iterating with a while loop. This is of course the classic issue when destructors throw, and I spent a while descending into that rabbit hole to understand the technical details and best practices.

In my case I found that the simplest and cleanest solution was to wrap f with code that sets and clears the flag:



void fWithFlagTrue() {
    /* complicated flow control, many return paths .. */
}


void f() {
    SetFlag(true);
    fWithFlagTrue();
    SetFlag(false);
    
}

This was rather unsatisfying because:

  1. I really like my original two-line patch. I set the flag at the top and with scope_guard I can ensure the flag is cleared on function exit.

  2. I really don't like my solution since it's a lot of boilerplate, and it seems that there should be a less tedious idiomatic solution.

I understand that having two active exceptions at once is problematic, and interrupting stack unwinding is very problematic. In my case if f throws then I want execution to end up in outer as I described above, and the state of the flag isn't relevant. If SetFlag throws the same applies: I just want execution to end up in outer. So I think my solution is long-winded but it's what I want logically. I'm just hoping there is something closer to my original two-line patch that can achieve this.

c++ scopeguard