c++中有一个东西叫做左值引用和右值引用,因为面向对象语言中有很多封装好的自定义类型容器,而这些容器又不像内置类型那样传值方便,有时候可能会有很大的深拷贝浪费于是有了左值引用:在函数传参时方便的传引用避免了传复杂的指针,而在返回之上直接传引用减少了不必要的深拷贝.而右值引用又在这基础上解决了传进来的引用如果是将亡值则直接进行转移拷贝.又进一步的减少了一次深拷贝.而在传返回值时若传回来的是一个临时变量的将亡值则转移拷贝又可以减少资源的浪费.例如若一个函数中生成了一个临时变量并需要将这个临时变量传出去,此时就不可以用传左值引用,若是使用传值则需要拷贝构造一个临时变量,然后将这个临时变量再考呗构造给外面用,此时调用了两次这个变量的构造函数,而用右值引用接收这个具有常性的临时变量,在转移拷贝此时就只是调用了一次构造函数就完成了传值.
右值引用的场景:
1:重载一些自定义类的拷贝构造与赋值运算符,使其判断传入将亡值的情况进行转移构造.
2:就是上面说的情况处理一些比较消耗大的传值返回.
3:重载一些自定义容器的插入函数,这个与第一种情况比较类似,也是判断将亡值的情况,一般的容器中的emplace和push接口都有重载这个右值引用.只不过emplace的优点在于在接口上传入匿名构造的元素他可以自己构造.比如vector<pair<K,V>>的容器若是push插入就需要用make_pair构造一个匿名pair传入或者初始化一个pair对象传入,而emplace不仅用上面的方法调用也可以直接传入K,V自己构造pair进行插入.
所以总而言之右值引用就是传进来的变量出去了也是释放,不如让我继续利用.
需要注意的是模版参数的右值引用既可以接受左值又可以接收右值,然后右值引用在经历过二次以后传参后就会发生右值属性的丢失,所以需要用到完美转发.格式为Forward(T)T为目标右值.
可以看到没有用到完美转发的都变成了左值.
一个小点:move函数可以让左值变得可以被右值引用.可以理解为加上了右值属性.
lambda表达式:有以下场景:
stl里面的sort函数可以根据仿函数模版参数传入不同的仿函数从而达到控制升序和降序的结果,这个函数可以去用库里面有的也可以自己去写.:
但是如果是需要按自定义类型的不同属性去排上面的仿函数肯定是不行的,所以得用到模版的特化:
但是这样又太繁琐了要根据不同的情况写好多种函数,这是lambda表达式就可以派上用场了.
他的格式为[函数作用域外的捕捉列表](传入的参数列表)->返回值类型{函数体}然后这个整体可以赋给一个auto自己推出来类型的对象,所以他可以像仿函数和函数指针那样用,就是说可以传给仿函数参数.因为他的底层本质就是一个重载()运算符的函数.只不过函数名是lambda<+系统分配的uuid.
上图中在sort函数中的仿函数模版参数位置传入了一个lambda表达式,[]中不需要向外部捕获变量所以为空而函数参数列表需要传入两个good结构体返回值类型是bool类型,函数实现部分是{}里面的.这样想要换排序的key就可以随时换很方便.[]可以捕获外面的变量,它分为一个传值捕获,和传引用.传值捕获的东西不可以改变,如果非要改变就加mutable关键字修饰然后再改但是没有什么用,要改变可以直接传引用改变.如果一次要捕获很多数据就直接用[=]或[&]全局捕获.
总而言之lambda用法和函数很像.他有实例化对象,也可以直接传表达式整体.
多线程:
一个程序中main函数就可以说是一个主线程,而在以前的学习中几乎都是一个程序跑一个线程,涉及到计算机组成原理的一些知识(还没学)反正多线程某些情况下跑的比单线程要快所以这里说一下多线程.
上面的代码,就是两个线程(加上main三个)对x自增计算,可以看到线程t1自增1000000次线程t2自增1000000所以理论结果应该是2000000次但是运行结果却不是这样
可以看到只自增了一百一十多万次,因为++x这句话分三部分组成,第一步是拿到这个x.第二部对这个x加一第三部放回这个x,两个线程都会有这三部,而这三步在每一步是都有可能被另一个线程影响,所以需要在++x这句话不能不影响,有下面两种常用的方法:
1:对一段代码上锁:时++x在执行时不受影响;如第一个图:
2:使用库里面的原子编程使++x成为一个指令,也可以避免冲突的情况.如图二
还有就是并不是上锁的代码越断越好,因为太短了线程会来回切的很频繁而导致变慢.
如果一个很庞大的数据量需要多线程来执行.如果像上面那样一次一个thread未免太慢了.,以你为thread是一个类型名,所以可以将它装入容器中,然后不断匿名实例化线程装入容器,让它自己跑.就像下图中所示,想vector中装入了n个线程,让他们自己跑.
可以看到mian函数中有一个join函数,因为main函数完了程序就完了,但是main函数里弄出来的线程还没有跑完,所以可以当作mian函数执行join方法时是在等t1线程执行结束.
以上代码的意思是用两个线程分别输出100以内的奇数和偶数,运行结果如下图:
可以看到两个线程挤压了屏幕输出导致输出错乱此时就需要想一个办法如何防止两个线程冲突输出,可以运用上锁和解锁来解决,在每次进行第一个for循环代码时对第二个线程上锁,第一个线程每次for循环完了后上给第二个解锁,然后第二个开始时对第一个上锁,结束后解锁,这样有序进行就可以解决了.
这样就解决了
标签:15,函数,右值,可以,线程,引用,多线程,lambda From: https://www.cnblogs.com/qjwxlj/p/17403327.html