C++中的每一个表达式要么是lvalue要么是rvalue。lvalue表示一个内存位置,而rvalue表示计算表达式的结果。数组
rvalue引用是对有名称变量的引用,并容许变量表示的内存经过lvalue引用来访问。ide
rvalue引用是对包含表达式结果的内存位置的引用。函数
总之,表达式的结果和函数内定义的变量都属于临时变量,即rvalue。spa
int && num {2*x+3}; //rvalue引用表达式的临时结果指针
int & num {x=5}; //lvalue引用code
常量引用:blog
void GetSet(int &num) { num += 1; }
Error (active) initial value of reference to non-const must be an lvalue.内存
void GetSet(const int &num) { num += 1; }
上面代码:只看第一个函数头GetSet(变量)是正确的,但GetSet(常量5)会被报错,由于编译器不容许对常量存在可能潜在的更改行为。ci
规定常量做为参数传递时需加const,即意味着不可更改。get
lvalue引用:
使用lvalue引用形参,能够编写直接访问调用者实参的函数,避免了按值传递中的隐式复制。若不打算修改实参,则只须要给lvalue引用类型使用const修饰符,以免意外修改参数。
其实,不管是按值传递、按址传递参数或引用都是编译器的规则,咱们须要熟悉参数在不一样状况下的传递,好的理解方式就是输出地址来观察。
void GetSet(int & num) { num += 1; } int main() { int v = 6; GetSet(v); cout << v<< endl; cin.get(); }
输出结果: 7 ,num变量值经过引用改变了,能够类比,变量的指针传址方式。
rvalue引用:
void GetSet(int && num) { num += 1; } int main() { int v = 6; GetSet(v); cout << v<< endl; cin.get(); }
编译器报错:Error (active) an rvalue reference cannot be bound to an lvalue
可知lvalue不能经过rvalue引用,有rvalue引用形参的函数只能经过rvalue实参来调用。
void GetSet(int && num) { num += 1; cout <<"num="<< num << endl; } int main() { int v = 6; int c = 3; GetSet(v+c); cout <<"v="<< v <<" c="<< c <<endl; GetSet(5); cin.get(); }
上面代码编译经过,结果以下:
编译器会为表达式的结果生成一个临时地址来存储数值。而常量字面值 5 ,被当成一个表达式处理,而且存储在函数引用形参的临时位置。
输出地址能够看出,常量在rvalue引用的时候和表达式同样处理了,即看作临时变量。
函数返回值的引用:
int* GetSet(int num) { num += 1; int result {num}; return & result; } int main() { int v = 6; int *ptr=GetSet(v); cout <<"ptr="<< *ptr << endl; }
本段代码能够运行,但编译器却给出了以下警告:
“Warning C4172 returning address of local variable or temporary”
缘由在于:从函数中返回的引用是临时变量的地址,应注意不要从函数中返回局部自动变量的地址。
能够使用动态内存分配为函数中的变量申请内存,因为动态内存分配的内存是一直存在的(在堆中),除非用 delete 销毁。即以下方式:
int* GetSet(int num) { num += 1; int *result{ new int {num} }; return result; } int main() { int v = 6; int *ptr=GetSet(v); cout <<"ptr="<< *ptr << endl;
delete ptr; }
观察下面两部分代码的不一样:
1、
double & lowest(double a[], int len) { int j{}; for (int i{ 1 }; i<len; i++) if (a[j]>a[i]) j = i; return a[j]; }
2、
double & lowest(double a[], int len) { int j{}; for (int i{ 1 }; i<len; i++) if (a[j]>a[i]) j = i; return & a[j]; }
引用是赋予存在变量的别名,因此实际返回的是数组元素a[j]的引用,而不是改元素包含的值。a[j]的地址用来初始化要返回的引用,该引用是编译器建立的,由于返回类型是引用。
但返回a[j]和返回&a[j]是不一样的。
返回&a[j],则指定的是a[j]地址,那是一个指针。因此,第二部分代码会被报错以下:
Error C2440 'return': cannot convert from 'double *' to 'double &'
由于指针和引用属于不一样类型。
Const 在传参引用中的潜规则的:
double refcube(const double &ra) { return ra*ra*ra; } long edge = 5L; double side = 3.0; double c1 = refcube(edge); double c2 = refcube(7.0); double c3= refcube(side+10.0);
上面代码中的函数调用都会产生临时变量:
edge虽然是临时变量,类型不正确,double引用不能指向long。
参数7.0和side+10.0类型虽然正确,但没有名称,编译器将生成一个函数期间调用的匿名临时变量。
而如今若是咱们去掉 const ,会发现编译器会报错:
Error:a reference of type "double &" (not const-qualified) cannot be initialized with a value of type "long"
Error:initial value of reference to non-const must be an lvalue
Why?
double refcube(double &ra) 是lvalue引用,要求使用知足类型的左值做为参数。
那么为什么 double refcube(double ra) 会经过编译。
由于直接调用和使用const同样编译器会产生 临时变量,只不过使用了 const 意味着不能修改参数。
固然此处代码是能够使用rvalue引用或const rvalue引用,但 Long 类型没经过报错以下:
Error:'double refcube(const double &&)': cannot convert argument 1 from 'long' to 'const double &&'