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

std::thread默认引用捕获引发未定义行为的原因解析

循环线程中索引打印异常的原因分析

先看出现问题的代码:

#include <iostream>
#include <vector>
#include <thread>

int main()
{
    std::vector<std::thread> threads;

    for (int i = 0; i < 3; i++)
    {
        threads.emplace_back([&](){
          std::cout<<"wrong value of i = "<<i<<std::endl;
        });
    }

    for (auto &thread : threads)
    {
        thread.join();
    }

    return 0;
}

问题根源:引用捕获循环变量导致的未定义行为

这段代码的核心问题是lambda通过引用捕获了循环变量i:

  • [&]表示引用捕获所有外部变量,lambda内部保存的是i的内存地址,而非创建线程时i的具体数值。
  • 主线程的循环会持续修改i的值:从0递增到1、2,最后循环结束时i会变成3(因为i<3的条件不满足时,i已经自增到3)。
  • 子线程的执行时机是不确定的——可能在主线程还在循环时执行,也可能在循环结束后才启动。当子线程执行lambda访问i时,读取的是该内存地址的当前值,而非创建线程时的i快照,因此会打印出错误的结果(比如多次输出3,或者混合输出1、2、3等),这属于C++中的未定义行为。

为什么[&,i]能正常运行?

[&,i]的捕获规则是:默认对外部变量使用引用捕获,但显式指定i按值捕获。

  • 按值捕获时,lambda会在创建线程的瞬间,复制一份当前i的数值作为自己的内部变量。
  • 后续主线程修改原i的值,完全不会影响lambda内部的i副本。每个子线程的lambda都持有各自创建时的i副本,因此能正确打印0、1、2这三个预期值。

额外补充:如果使用C++11及以后的范围for循环(如for (int i : {0,1,2})),循环变量i在每次迭代中都是全新的变量,此时用引用捕获也不会出现问题,但传统for循环中的i是同一个变量贯穿整个循环,必须按值捕获才能避免未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 10:17:36