Search code examples
c++c++17std-call-once

Can std::call_once be reset?


I wrote a function a while ago, based on Unreal Engine 4's blueprint implementation, that invokes a callable exactly once until it is reset:

template<typename Callable>
void DoOnce(Callable&& f, bool reset = false, bool start_closed = false) noexcept {
    static bool once = start_closed;
    if(!once) {
        once = true;
        std::invoke(f);
    }
    if(reset) {
        once = false;
    }
}

Today I learned std::call_once exists, works across threads, works with callables that have arguments, tests for exception-safety, and basically wraps around std::invoke like mine does (the MSVC implementation at least).

That sounds great and, where possible, I prefer calling a pre-existing function over writing my own anyway.

Like Unreal's documentaion suggests, there are times that I may need to invoke the callable again by resetting the internal flag; can std::call_once be reset in order to allow the underlying callable to be invoked again?


Solution

  • The standard isn't kidding when they call it "once_flag". It's a flag that only gets set once.

    You can of course call the function multiple times, with different once-flag objects. But to do this properly, you need to hand each thread that might attempt to call it the new once-flag object. It can't just be a global or static object somewhere; you have to actually marshal each new invocation out to all of the threads that want to call it.