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?
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.