You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:11:35