线程传参,是否有副本。以及C2672“std::invoke”错误
线程传参,值传递和单独的&传递,线程都会保留一份副本,不会对函数外的值造成影响。外边的值释放了,也不影响线程函数里的值。有种普通函数值传递的感觉,里外互不相干。
指针传递,& + std::ref 组合,才是传真身,不会有副本。等效普通函数的指针传递和引用传递了。此时需要注意生命周期内的内存值的改变和释放,否则可能异常。
指针传递:
void threadFunction(int* ptr) { // 在线程中修改ptr指向的值 } int main() { int x = 0; std::thread t(threadFunction, &x); t.join(); return 0; }
& + std::ref 组合
void threadFunction(int& ref) { // 在线程中修改ref的值 } int main() { int x = 0; std::thread t(threadFunction, std::ref(x)); // 使用std::ref确保以引用方式传递 t.join(); return 0; }
当把std::ref去掉后,会报C2672“std::invoke”错误。这是编译器的善意提醒,认为你想传真身,但是传的不对,可以加上std::ref,或者函参用const修饰。
本质原因多线程传参报错 :错误 C2672 “std::invoke”: 未找到匹配的重载函数_error c2672: “invoke”: 未找到匹配的重载函数-CSDN博客
但是编译器也不足够强大,传结构体时,就不会报这个错误
struct MyStruct { int a = 0; }; void threadFunction(MyStruct& ref) { // 在线程中修改ref的值 ref.a = 20; } int main() { MyStruct ms; std::thread t(threadFunction, ms); //不会报错,传的是副本 t.join(); return 0; }
【单独的&传递】
函参推荐写法:
简单类型 变量名。对于简单类型,如int等,用值传递安全,不要用引用。
const 类 &类对象。对于类、struct等用引用。这样编译器不会报错,而且虽然不是传真身,但是减少了一次拷贝构造。
thread的机制是先把传的类对象构造出来,即临时对象(第一次构造,注意不是拷贝构造),对临时对象进行拷贝(第二次构造,拷贝构造),再传到函参,值传递方式会再次拷贝构造(第三次构造,拷贝构造)。
void MyThread1(int nVal) {} void MyThread2(const Test &t) {}
参考