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
相关产品推荐
相关产品推荐

