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

不调用std::future::get()时下述C++代码是否存在潜在问题?

问题:不调用std::future::get()是否存在代码风险

如果不调用std::future::get(),下方代码片段是否存在潜在问题?
我进行了多次测试,发现即使std::async启动的任务需要耗费较长时间才能执行完毕,不调用std::future::get()时上述代码似乎也能正常运行,这一结果完全超出我的预期。

#include<future>
#include<iostream>
#include<array>
#include<algorithm>
#include<thread>
#include<vector>

std::array<int, 100000> arr;
int sum=0;

struct Wrapper
{   
    void consume()
    {
        std::cout << "consumer:" << std::this_thread::get_id() << std::endl;
        std::for_each(arr.begin(), arr.end(), [](int val) {sum+=val; });
    }

    void produce()
    {
        std::cout << "producer:" <<std::this_thread::get_id() << std::endl;
        
        int a=0;
        while(true)
        {
            if(a++>1e9)
            {
                break;
            }
        }
    }
};


int main()
{
    std::fill(arr.begin(), arr.end(), 1);

    std::cout << "main:" <<std::this_thread::get_id() << std::endl;

    Wrapper wrap;

    std::vector<std::future<void>> vec;
    vec.push_back(std::async(std::launch::async, &Wrapper::produce, &wrap));
    vec.push_back(std::async(std::launch::async, &Wrapper::consume, &wrap));

    #ifdef WAIT  //Is there any potencial problem if the block below does not run?
    for(auto& future:vec)
    {
        future.get();
    }
    #endif
}

解答

你测试时看到的“不调用get也正常运行”不是巧合,是C++标准给std::async返回的std::future加的特殊规则:这类future在析构时会阻塞,直到关联的异步任务执行完成。你代码里的vec是main函数内的局部变量,main退出前会先析构vec,vec内部存储的两个future会依次析构,自动等待produce和consume两个任务跑完,所以不会出现任务没跑完程序就退出的情况。

但这种写法依然存在不少潜在问题:

  • 阻塞位置完全不可控:你对析构阶段的隐式阻塞没有感知,如果后续在main函数末尾、vec析构之前加了需要及时执行的逻辑(比如上报运行结果、释放外部句柄、输出收尾日志),这些逻辑的执行时机不会符合你的预期;如果异步任务出现死锁、无限循环,程序会直接卡死在变量析构阶段,问题排查难度极高。
  • 隐式等待行为不具备通用性:只有std::async返回的、绑定异步运行任务的future才有析构阻塞的特性,如果你后续修改代码,把启动策略改成std::launch::deferred,或者future是从std::promise、std::packaged_task拿到的,future析构时不会做任何等待,程序会直接退出,异步任务可能执行到一半被强制终止,引发数据损坏、崩溃等问题。
  • 代码本身还有独立于future调用的并发问题:全局变量sum在consume线程中被修改,全程没有加锁或者原子保护,属于多线程数据竞争,是标准定义的未定义行为,你测试时运行正常只是运气好,换编译选项、换平台、换硬件都可能出现计算结果错误、程序崩溃的问题。

实际开发中不要依赖future析构的隐式等待,显式调用get()或者wait()可以明确标注等待的位置,代码可读性和可维护性都更好。


内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 22:31:00