线程传参,是否有副本。以及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)
{}

 

参考 

C++——多线程(传参注意事项)_c++ 多线程 参数传递-CSDN博客

个人C++11多线程学习笔记_c++ cond.wait-CSDN博客

posted @ 2024-07-20 16:42  夕西行  阅读(59)  评论(0编辑  收藏  举报