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

C++线程函数按值接收对象:为何std::ref(obj)可编译?

问题:用std::ref传递对象给线程时,原对象会成为多线程共享变量吗?
#include <iostream>
#include <thread>

template<int Num>
class MyClass {
public:
    MyClass(int val) : val_(val) {}

    // 拷贝构造函数
    MyClass(const MyClass& other) : val_(other.val_) {
        std::cout << "Copy constructor called" << std::endl;
    }

    // 移动构造函数
    MyClass(MyClass&& other) noexcept : val_(other.val_) {
        std::cout << "Move constructor called" << std::endl;
    }

private:
    int val_;
};

template<int Num>
void threadFunction(MyClass<Num> myObj) {
    std::cout << "Inside thread" << std::endl;
}

int main() {
    MyClass<1> obj(42);

    std::thread t1(threadFunction<1>, obj); // <-- 按值传递
    std::thread t2(threadFunction<1>, std::ref(obj)); // <-- 用std::ref传递

    t1.join();
    t2.join();

    return 0;
}

我原本希望按值传递对象给线程,确保每个线程操作自己的独立副本(比如t1的情况)。但创建t2时,我用了std::ref(obj)来传递对象。我的线程函数定义是按值接收参数的,想问这种情况下,原obj会不会变成多线程间的共享变量?


不会。核心原因在于你的threadFunction是按值接收参数的,哪怕用std::ref(obj)传递,最终线程函数里的myObj仍然是原obj的独立拷贝,而非直接引用原对象:

  • 对于t1:直接传递obj时,std::thread会先把obj拷贝到线程内部的存储区域,再将这个拷贝的对象以右值形式传递给threadFunction,触发移动构造函数(如果类支持的话),最终线程操作的是完全独立的副本。
  • 对于t2:传递std::ref(obj)时,std::thread实际拷贝的是std::reference_wrapper类型的包装器(而非原对象)。当调用threadFunction时,这个包装器会被解引用为原obj的左值引用,接着用这个引用来构造线程函数的参数myObj——也就是触发拷贝构造函数生成新的副本。所以t2的线程函数操作的依然是独立的副本,原obj并没有被多个线程直接共享。

如果想要让多个线程直接共享原对象,你需要把threadFunction的参数改成引用类型(比如void threadFunction(MyClass<Num>& myObj)),此时用std::ref(obj)传递才会让线程直接操作原obj,这时才需要考虑线程安全问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 06:48:22