左值引用和右值引用
左值引用:对左值进行引用
右值引用:对右值进行引用
左值和右值区别:左值可以取地址,右值不可以
左值可以使用move来变成右值
//左值引用
int a=0;
int& r1=a;
//右值引用
int&& r2=10;
int x=1,y=2;
int&& r3=x+y;
const 可以引用右值也可以引用左值
int x=1,y=2;
const int& r1=x+y;//引用右值
const int& r2=x;//引用左值
左值引用场景
1、函数传参:减少拷贝
2、函数返回值:出了作用域没有被销毁的对象,可以用左值引用。
左值引用缺点:做返回值时,返回值出了作用域被销毁,就会拷贝构造,开一个临时空间
右值引用的意义
函数返回值出了作用域被销毁时,右值引用不需要拷贝构造开临时空间,只需要移动构造
注意 :当构造和拷贝构造在同一行时会优化为一次构造
内置类型右值:纯右值
自定义类型右值:将亡值
左值引用和右值区别
总结:左值引用减少拷贝原理:取别名,直接使用
右值引用:移动构造和移动赋值,右值(将亡值)转移资源
左值右值引用出现的问题
这里调用函数传参时,传入的是左值的地址,编译器将其解释为一个右值
函数期待接收的是一个左值引用,所以就会报右值引用问题
直接传参channel就可以了
万能引用
要调用一个函数,传入参数可以是右值也可以是左值
左值时,&& 会折叠变成一个&
template<typename T>
void PerfectWord(T&& t)
{
Fun(t);
}
完美转发
上述代码中t可能是左值也可能是右值,当传入的是右值,在调用Fun可能退化成左值
Fun(forward<T > (t))可以保持其属性不被改变
lambda表达式
表达式:[capture-list] (parameters) mutable -> return-type { statement }
1、[capture-list] 捕捉列表,捕捉上下变量给lambda函数
2、(parameters) 参数列表,没有参数时可以省略
3、mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
4、 -> return-type: 返回类型,没有返回值时可以省略,函数返回类型明确时省略编译器会自动推
5、{ statement }函数体,可以使用参数列表和捕捉列表的值
作用:需要多个operator()时,一般用于替换仿函数operator()
//仿函数比较大小
struct Compare
{
bool operator()(const Goods& gl, const Goods& gr)//Goods 商品类
{
return gl._price <= gr._price;
}
};
//lambda
bool compare=[](const Goods& gl, const Goods& gr){return gl._price <= gr._price;};
包装器
function包装器
可以调用的对象:仿函数(函数对象),函数指针,lambda
当指定了参数和返回类型,调用仿函数、函数指针、lambda,函数模板会被实例化多次,效率降低。
这时就可以使用function包装器,模板只会实例化成一份
//函数指针
int f(int i)
{
retrun i+1;
}
//仿函数
struct Functor
{
int operaotor()(int i)
{
return i+2;
}
};
functional<int(int)> f1=f;
functional<int(int)> f2=Functor();
functional<int(int)> f3=[](int i)->int{return i};//lambda
bind包装器
可以指定传参
#include <functional>
int Plus(int a, int b)
{
return a + b;
}
class Sub
{
public:
int sub(int a, int b)
{
return a - b;
}
};
//_1传给Plus第一个参数,_2传给第二个参数
std::function<int(int, int)> func1 = std::bind(Plus, placeholders::_1,
placeholders::_2);
cout<<func1(10,20)<<endl;