std::thread构造时参数默认按值拷贝,传引用需显式用std::ref/cref;移动语义后原变量失效;lambda捕获引用需确保生命周期;Windows下栈小易失败,推荐shared_ptr管理大对象。

std::thread 构造时传参会被拷贝而不是引用
直接把变量地址传给 std::thread 构造函数,实际执行时很可能访问到已销毁或悬空的内存。因为默认按值传递,连 std::ref(x) 都会被包装成副本——除非你显式告诉它“我要引用”。
- 想传引用:必须用
std::ref(var)或std::cref(var)包一层,否则传进去的是拷贝 - 传指针没问题,但要确保指针指向的对象生命周期 > 线程运行时间
- 移动语义可用:比如传
std::move(str),原对象之后不能再用 - lambda 捕获同理:
[&x]{...}是引用捕获,但线程启动后 x 若已析构,照样 UB
std::thread 传参时 std::move 后原变量失效
对右值或可移动对象(如 std::string、std::vector)用 std::move 传参后,主线程里原变量进入有效但未定义状态——不是“清空”,而是“别再碰它”。常见误操作是 move 后还去 print 或 size()。
- 传完立刻置空原变量(如
str = "")是自检好习惯,但不解决根本问题 - 如果函数参数是
const T&,用std::move反而触发拷贝,白忙活 - 优先考虑用
std::shared_ptr共享所有权,比手动管理生命周期更稳
lambda 捕获列表和 std::thread 参数混用容易重复转移
写 std::thread{[x](int y){...}, 42} 时,x 被拷贝进 lambda,再被 thread 拷贝一份;若写成 [&x] 又可能悬空。两层捕获+传参容易叠 Buff,结果不是多拷贝就是野指针。
- 只在必要时捕获:能当参数传的,就别塞进捕获列表
- 捕获引用 + 外部保证生命周期 > 用
std::ref再传一次 - 错误示范:
std::thread{[&x](){ use(x); }, std::ref(x)}—— x 被引用两次,风险翻倍 - 正确做法:要么
std::thread{[](int val){ use(val); }, x},要么std::thread{[&x](){ use(x); }}(且确保 x 活得够久)
Windows 下 std::thread 构造失败常因栈大小不足
VC++ 默认线程栈只有 1MB,传大对象(比如几 MB 的 std::vector<char></char>)进 std::thread 构造函数,可能直接抛 std::system_error,错误码是 resource_unavailable_try_again,但没提示栈不够。
立即学习“C++免费学习笔记(深入)”;
- Linux/macOS 通常默认 8MB,不容易撞上;Windows 尤其要注意
- 解决方法不是调大栈(麻烦且不跨平台),而是改用堆分配 + 智能指针传参
- 临时 workaround:用
_beginthreadex手动指定栈大小,但失去std::thread的 RAII 优势 - 最稳妥:把大数据封装进
std::shared_ptr,只在线程里访问,不在线程构造时搬运








