Reputation: 3650
Some time ago I was looking for a way to invoke std::async
without the need of storing std::future
, thus not blocking the execution at the end of the scope. I found this answer which uses a captured std::shared_ptr
for an std::future
, therefore allowing to make a nonblocking call to std::async
.
Another way of deferring a destructor invocation is to prevent it from to be called at all. This can be achieved with in-place construction with operator new
.
Consider this version that uses a static thread local storage for an in-place constructed std::future<void>
:
template <class F>
void call_async(F&& fun) {
thread_local uint8_t buf[sizeof(std::future<void>)] = {0};
auto fut = new(buf) std::future<void>();
*fut = std::async(std::launch::async, [fun]() {
fun();
});
}
This version will not produce any heap-allocation related overhead, but it seems very illegal, though I am not sure why in particular.
I am aware that it is UB to use an object before it has been constructed, which is not the case. I am not sure why not calling delete
in this case would resolve in UB (for heap allocation it is not UB).
Possible problems that I see:
std::promise
I suppose)UPDATE
Constructing an object in the static storage directly (as has mentioned IlCapitano in the comments) will block each time a move assignment is called (shared state will be destroyed blocking the thread which has removed last reference to it).
Not calling a destructor will case a leak because of not released references to the shared state.
Upvotes: 6
Views: 950
Reputation: 76498
Calling std::async
and ignoring the result sounds like "fire and forget". The simplest way to do that is to not use std::async
, but to create a detached thread:
std::thread thr(func, data...);
thr.detach();
Upvotes: 1
Reputation: 63162
It's undefined behaviour to end the lifetime of a non-trivial object without calling it's destructor, which happens as soon as there is a second call_async
invocation.
"heap-allocation related overhead" is a misnomer if the only alternative is undefined behaviour. The future
returned by async
has to live somewhere.
The updated code has defined behaviour: it waits for the previous invocation to be done before launching the next one.
Upvotes: 3