C11中有左值引用和右值引用
左值引用
对一个变量的别名,不会调用拷贝构造,对别名的操作影响原值
eg:
运行结果:
右值引用
对匿名变量的引用,提出右值引用的原因:充分利用在函数调用过程中产生的临时变量,对这个临时变量达到最大限度的使用率
常用的匿名变量(对象):
fun(A a()); //此时生产了一个临时变量,且无名,这就是右值
int add(int a, int b)
{
return (a + b); //此时的(a+b)的结果就是一个临时变量,且无名,这就是右值
}
右值引用如何使用
并不是变量自动就会变成右值引用,需要用户按右值引用的方式定义接口、定义变量,才会触发右值引用,举个例子:
1)
fun (A a) { //再怎么传也不会变成右值引用
//TODO
}
如果用户使用 fun(A()); //则就是调用一个普通的函数
2)
如果想使用右值引用就需要用户按右值引用定义接口,才会调用到这个右值引用
fun(A&& a){
//TODO
}
fun(A()); //这时编译器发现你有定义相关接口,就会去调用右值引用的函数了
记住: 右值引用可以优化过程中产生的临时变量,但并不代表你什么都不做它就能优化,如果你想优化,需要你手动实现相关接口才行; 右值引用只是一个功能,你可以选择用或不用。
上面1)和2)说的都是调用函数中的形参问题,下面说说变量问题;
int a=2, b=3;
int c = add(a, b); //c就是再普通不过的一个左值,add先产生一个临时变量然//后再将临时变量赋值给c
int&& d = add(a, b); //d就是一个右值,add过程中产生一个临时变量,d就是这//个临时变量的一个“引用”,加引号是因为说d是一个偷盗//者更合适,它把那个临时变量给偷过来了
注意:此处使用int并不是很明显,如果使用一个T,T中包含指针数组,大家可能更容易明白
上面的c和d是程序员用户自己写的,他不在乎过程中多一次拷贝就按c的方式写;如果他是一个处女座的程序员,他可能更喜欢使用d的方式;再次重申:右值引用是一功能选项,你可以选择用与不用。
扩展一
上面说的都是最正常的情况,即只对匿名变量(对象)使用右值引用,但是我们总是喜欢知道了一个规则后,就千方百计利用这个规则,比如下面这种使用场景:
void test(){
T t;
fun(std::move(t)); //将t转换成了一个右值引用
}
void fun(T& t); //左值引用
void fun(T&& t); //右值引用
举一个可能用到的场景:
void print_(std::string& str) {
std::cout<<str<<” ”;
}
void print_(std::string&& str) {
std::cout<<str<<” ”;
}
void test() {
std::string str(“Hello World!”);
print_(str); //左值引用,后面str内容不变
print_(std::move(str)); //转为右值引用 ,表示str可以被移动,但是否移动看后面接口的选择了,由于此处仅是调用一个接收右值引用传递的方法,
//并不会修改str,即并没有进行move操作,所以调用完成后str内容不会发生改变
}
注意std::move的本质,它其实就是一个转换函数,将给定的类型转化为右值引用,而并不是真正地“移动”了资源.