std::thread 构造即启动,无法延迟启动;它不可赋值,必须在构造时传入可调用对象,如 lambda、函数指针等。

std::thread 构造即启动,不能延迟调用
创建 std::thread 对象的那一刻,线程就立即启动了——它没有“创建后手动 start”的阶段。这是和 Java 或 Python 的 Thread 类最根本的区别,也是新手最容易误解的地方。
常见错误是写成这样:
std::thread t;
t = std::thread([]{ /* do work */ }); // 编译失败:std::thread 不可赋值正确做法只有一种:在构造时传入可调用对象(函数指针、lambda、绑定表达式等):
std::thread t([]{ std::cout-
std::thread t(func, arg1, arg2);(func是普通函数或成员函数指针) - 若要传成员函数,必须显式提供对象实例:
std::thread t(&MyClass::run, &obj, 42);
必须 detach 或 join,否则程序会 terminate
当一个 std::thread 对象析构时,如果它仍表示一个“可加入的”(joinable)线程,C++ 标准强制调用 std::terminate() —— 程序直接崩溃,不抛异常,也不打印提示。
立即学习“C++免费学习笔记(深入)”;
所以你必须在对象生命周期结束前明确决定线程归属:
- 用
t.join():主线程等待它结束,适合需要同步结果的场景 - 用
t.detach():线程后台运行,与t对象解绑,之后不能再控制或等待它 - 绝不能让
std::thread对象(尤其是局部变量)在未join()或detach()的情况下离开作用域
典型坑点:if 分支里只在某个条件下 join(),但其他路径没处理,导致析构时仍 joinable。
传递参数要注意值拷贝 vs 引用捕获
std::thread 构造函数对参数默认按值拷贝——即使你传的是引用,也会被复制一份。想真正传引用,必须用 std::ref(x) 包裹;想传右值引用(比如移动语义),要用 std::move(x)。
例如:
int x = 42;
std::thread t([&x]{ std::cout << x; }); // ❌ lambda 捕获引用,但线程可能在 x 生命周期外执行
std::thread t([](int& y){ std::cout << y; }, std::ref(x)); // ✅ 显式传引用更安全的做法是:优先传值,或确保被引用对象的生命周期覆盖整个线程执行期。不要依赖栈上局部变量的引用。
不能复制,只能移动;临时对象容易出问题
std::thread 不可拷贝(删除了拷贝构造和拷贝赋值),只支持移动。这意味着:
- 不能放进
std::vector<:thread></:thread>然后用push_back(t)(会尝试拷贝) - 必须用
push_back(std::move(t))或直接 emplace:threads.emplace_back([]{...}); - 写
return std::thread(...);是合法的(返回值会被移动)
另一个隐藏陷阱:临时 std::thread 对象(如函数返回、表达式中构造)一旦语句结束就析构,若未 join() 或 detach(),立刻 terminate。所以永远不要写 std::thread(...); 这种孤立语句。


















