std::async执行机制探究:代码运行差异及构造调用疑问
关于C++ std::async中Task对象构造与调用逻辑的疑问解答
先看你提供的测试代码:
#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'; }
两种模式的运行输出
- 使用
std::launch::async时的输出:
0 ctor move-ctor move-ctor dtor func() dtor dtor 3
- 使用
std::launch::deferred时的输出:
0 ctor move-ctor move-ctor dtor dtor dtor 3
你的疑问解答
1. 为什么会出现第二次移动构造?
你的猜测完全正确!第二次移动构造确实和std::future脱不了干系,咱们一步步拆解流程:
- 首先,你调用
std::async时传入的Task()会创建一个临时Task对象,触发第一次默认构造(对应输出里的ctor)。 - 接着,这个临时对象会被移动到
std::async的函数参数中,这是第一次移动构造(第一个move-ctor)。 - 最后,
std::async内部需要把任务对象存到和std::future关联的共享状态里——哪怕你没接收std::async返回的future,这个共享状态依然会被创建。把任务移到共享状态的过程,就触发了第二次移动构造(第二个move-ctor)。
对应的三次析构也很清晰:临时对象、std::async参数里的对象、共享状态里的对象,各自生命周期结束时都会调用析构函数,所以输出里有三次dtor。
2. deferred模式下为什么没调用operator()?
这是std::launch::deferred的核心设计:它不会立刻启动任务,而是延迟到你主动调用返回的std::future的get()或wait()方法时才执行。
但在你的代码里,std::async返回的std::future是个临时对象,它的生命周期在std::async调用结束后就直接结束了——根本没机会触发任务执行!所以operator()完全不会被调用。
而std::launch::async模式下,系统会立刻创建新线程执行任务,不管你有没有接收future,所以func()会被正常调用。
内容的提问来源于stack exchange,提问作者vollitwr
相关产品推荐
相关产品推荐

