vollitwr
vollitwr

Reputation: 439

How exactly std::async is executed?

I wonder how does the following code work?

#include <thread>
#include <future>
#include <set>
#include <iostream>
struct Task;
std::set<const Task*> dead_tasks;
struct Task
{
   ~Task() { dead_tasks.insert(this); std::cout << "dtor\n";}
   Task() { std::cout << "ctor\n";}
   Task(Task&&) { std::cout << "move-ctor\n";}
   void operator()() const { std::cout << "func()\n"; }
};
int main(){
   std::cout << dead_tasks.size() << '\n';
   std::async(std::launch::async, Task());
   std::cout << dead_tasks.size() << '\n';
}

This code prints

0 ctor move-ctor move-ctor dtor func() dtor dtor 3

If we use std::launch::deferred instead of std::launch::async we will get

0 ctor move-ctor move-ctor dtor dtor dtor 3

So in the latter we miss the member function call. Why? I can understand the presence of the call to the default constructor and the call to the move constructor. Task() calls the default constructor, then std::async does a call to the move constructor... However I missed the idea behind the second call to the move constructor and the call to the member function. I can think that the second move constructor is called by std::future, can't I?

Upvotes: 1

Views: 297

Answers (1)

Jodocus
Jodocus

Reputation: 7591

So in the latter we miss the member function call. Why?

Because the call is, well, deferred. It will only start once you actually request for its results, e.g. by calling get() on the future (which you didn't):

auto fut = std::async(std::launch::deferred, Task());
fut.get();

I can think that the second move constructor is called by std::future, can't I?

This is rather implementation-defined whether and how many calls to a copy-constructor there will be. Building it e.g. in clang gave me even three calls to the move-constructor. Thus, just don't bother about it. But if you do, you have to look into the standard library implementations themselves, if available.

Upvotes: 2

Related Questions