当前位置: 首页 > news >正文

完美转发、C++11中与线程相关的std::ref

目录

模板中的万能引用

std::forward实现完美转发

C++11中与线程相关的std::ref

线程函数参数

用函数指针作为线程函数

用lambda表达式作为线程函数


模板中的万能引用

void Func(int& x)
{cout << "左值引用" << endl;
}
void Func(int&& x)
{cout << "右值引用" << endl;
}
void Func(const int& x)
{cout << "const左值引用" << endl;
}
void Func(const int&& x)
{cout << "const右值引用" << endl;
}template<typename T>
void PerfectForward(T&& t)
{Func(t);
}int main()
{PerfectForward(10); // 右值int a;PerfectForward(a); // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b); // const左值PerfectForward(std::move(b)); // const右值return 0;
}

全都是左值引用

1、模板中的&&不代表右值引用,而是万能引用,既能接收左值又能接收右值,后续使用中都退化成了左值。
2、模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力。
3、我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用到完美转发 。

如果将上面的函数模板改那为普通的函数,那么就限制了接收的类型,只能接收右值(后续也会被退化成左值),无法接收左值,被const修饰的变量也是左值,即使它不能被修改。

std::forward实现完美转发

template<typename T>
void PerfectForward(T&& t)
{Func(std::forward<T>(t));
}

std::forward 完美转发:变量为左值/右值传入函数模板中(函数模板参数T&&),该形参需要传入函数模板中调用的一个函数时,该形参保持原来的属性(即在传入函数模板之前的属性)传入。

下面可以看到右值引用a传入func函数时出现报错(无法将右值引用绑定到左值),这因为右值引用a此时已经变为了可以被修改的左值,这一点需要注意。

要想成功传参到func函数中可以使用std::move或std::forward,如下:

move:将左值a转换为右值。

forward:让右值引用b保持原来保持原来3的右值属性。

注意:左值引用具有左值属性,右值引用不具有右值属性(右值引用被转换为了左值引用),右值引用可以被修改。

C++11中与线程相关的std::ref

要想在从线程内部改变外部主线程中的变量,可以将该外部变量传入到创建的线程对象中改变,从线程如何保证有效的改变这个外部变量就是一个问题。

用函数指针作为线程函数
线程函数的参数是以值拷贝的方式拷贝到线程栈空间中的。
#include <thread>
#include <mutex>
using namespace std;
mutex m;
int a = 9;
void ThreadFunc1(int& x) //参数类型为int是无法实现修改外部变量a的目的
{m.lock();x += 10;m.unlock();
}
int main()
{// 在线程函数中对a修改,不会影响外部实参,因为线程函数参数虽然是引用方式,但其实际引用的是线程栈中的拷贝thread t1(ThreadFunc1, a);//编译时会报错   传入到thread中的外部变量a,如果要改变a的话就必须是ref(a)t1.join();cout << a << endl;// 如果想要通过形参改变外部实参时,必须借助std::ref()函数thread t2(ThreadFunc1, std::ref(a)); //编译正常t2.join();cout << a << endl;return 0;
}

void ThreadFunc2(int* x)
{m.lock();*x += 10;m.unlock();
}
int main()
{thread t3(ThreadFunc2, &a);t3.join();cout << a << endl;return 0;
}

用lambda表达式作为线程函数
int main()
{int x1 = 0;int x2 = 0;thread t1([x1]()mutable{x1++;}); //也无法改变外部的x1,因为值传递捕捉,在捕捉列表中的是x1的拷贝thread t2([&x2](){x2++;});t1.join();t2.join();return 0;
}

x1仍然是0,x2变为了1。

结论:当线程函数是lambda表达式时,将要修改的外部变量引用传递捕捉到捕捉列表中,就可以修改该外部变量了。

关于lambda中的mutable:当引用传递捕捉变量,lambda默认不会对该引用加const;当值传递捕捉变量,lambda会默认对该值加const,可以使用mutable剔除该const修饰。


http://www.mrgr.cn/news/31442.html

相关文章:

  • IDEA配置全局的maven环境
  • 《深度解析 C++中的拷贝构造函数:概念、作用与实践》
  • Vue学习记录之六(组件实战及BEM框架了解)
  • 渐变色代码主题你受得了吗
  • 固执和坚持99%的人不作区分
  • C++_CH18_构造函数与析构函数
  • 【宠粉赠书】大模型RAG实战:RAG原理、应用与系统构建
  • 每日奇难怪题(持续更新)
  • 360手机黑科技“位置穿越”功能修复 360位置穿越使用
  • 7个提升网站分页体验的 CSS 和 JavaScript 代码片段
  • 双token无感刷新
  • Python 类的继承
  • Generative Models from the perspective of Continual Learning【小白读论文】
  • 如何使用Spring Cloud Gateway搭建网关系统
  • 关于组织参加“2025第十四届国际生物发酵产品与技术装备展览会(济南)”的通知
  • Docker学习
  • 牛客小白月赛101(栈、差分、调和级数、滑动窗口)
  • Ansible部署openstack案例
  • mysql学习教程,从入门到精通,SQL 删除表(DROP TABLE 语句)(20)
  • [python3] 处理函数的重试