什么是引用?
引用就是对变量起一个别名,而变量还是原来的变量,并没有重新定义一个变量。例如下面的例子:
1 #include<iostream> 2 using namespace std; 3 4 5 int main() 6 { 7 int a = 10; 8 int& n = a; 9 cout<<a<<endl; 10 cout<<n<<endl; 11 cout<<&a<<endl; 12 cout<<&n<<endl; 13 14 return 0; 15 }
程序的运行结果为:
我们可以看到变量a和变量a的引用(别名)n所指向的就是同一片空间,而且别名n并没有创建一个新的变量
在引用的时候我们应该注意一些问题:
1.一个变量可以有多个别名2.引用必须初始化3.引用只可以在变量初始化的时候引用一次,之后不可以在引用其他的变量(这个想要引用其他的变量几乎是无法实现,反正我没办法)
常引用
现在我们了解了什么是引用,而常引用是非常容易出现错误的一种引用,下面我们展开讨论
以下代码就是相关的用法:
1 int main() 2 { 3 int d1 = 4; 4 const int & d2 = d1; 5 d1 = 5; // d1改变d2的值也会改变。 6 // d2 = 6; // 不能给常量(不能被修改的量)赋值 7 const int d3 = 1; 8 const int & d4 = d3; 9 // int&d5 = d3; 10 const int & d6 = 5; // 常量具有常性,只有常引⽤可以引⽤常量 11 double d7 = 1.1; 12 // int& d8 = d7; //d7是double类型,d8是int,d7赋值给d8时要生成一个临时变量 13 //也就是说d8引⽤的是这个带有常性的临时变量,所以不能赋值。 14 const int& d9 = d7; 15 return 0; 16 }
从以上的代码中我们就可以知道const引用时应该注意的问题。
引用可以作为函数的参数也可以作为函数的返回值来使用,但是我们在使用的时候应该注意些什么呢?
1.引用作为函数的参数时
在函数传参的时候,在C语言中有两种方式,一种是值传递,还有一种是址传递,也就是指针传递,而在C++中我们则引入了引用传递。这三种传递的方式各有各的特点的,这里我们着重说一下引用传递的特点
1 #include<iostream> 2 using namespace std; 3 #include <Windows.h> 4 struct BigData 5 { 6 int array [1000]; 7 }; 8 void DealBigData1(BigData& x) 9 { 10 x.array[0] = 0; 11 x.array[1] = 1; 12 x.array[2] = 2; 13 } 14 void DealBigData2 (BigData x) 15 { 16 x.array [0]= 0; 17 x.array [1]= 1; 18 x.array [2]= 2; 19 } 20 void TestReference() 21 { 22 BigData bd ; 23 int begin = GetTickCount (); 24 for (int i = 0; i < 1000000; ++i ) 25 { 26 DealBigData1(bd); 27 } 28 int end = GetTickCount (); 29 cout<<"cost time:" <<end - begin<<endl ; 30 begin = GetTickCount (); 31 for (int i = 0; i < 1000000; ++i ) 32 { 33 DealBigData2(bd); 34 } 35 end = GetTickCount (); 36 cout<<"cost time:" <<end - begin<<endl ; 37 } 38 int main() 39 { 40 TestReference(); 41 return 0; 42 }
以上代码的运行结果为:
从运行结果我们不难看出相比于传值而言,传引用无疑极大地提升了程序的性能。
2.引用作为函数的返回值时
1 int& Add (int d1, int d2) 2 { 3 int ret = d1 + d2; 4 return ret ; 5 } 6 void test() 7 { 8 int a = 3, b = 4; 9 int c = Add( a, b ); 10 cout<<"c:" <<c<< endl; 11 }
上面这段代码是错误的用法,因为用引用接收了一个局部或临时变量的地址,在我们编译的时候回报出如下的警告:
这里是因为函数在返回的时候会创建一个临时变量,而我们在以引用作为函数的返回值的时候,引用的是这个临时变量,我们都知道临时变量在函数运行完毕后会销毁的,那样这种写法毫无疑问是错误的不推荐的。
而下面的代码则是以传值作为函数的返回值,是正确的,当我们要以引用作为函数的返回值的时候,我们应该return一个以引用传递的参数,那样也就是正确的。
1 int Add1 (int a, int b) 2 { 3 int ret = a + b; 4 return ret; 5 } 6 int& Add2(int& a, int b) 7 { 8 int ret = a + b; 9 return ret; 10 } 11 void test1() 12 { 13 int ret = Add1(1, 2); 14 cout<<"ret:" <<ret<< endl; 15 } 16 void test2() 17 { 18 int a = 3, b = 4; 19 int c = Add2( a, b ); 20 cout<<"c:" <<c<< endl; 21 } 22 int main () 23 { 24 test1(); 25 test2(); 26 return 0; 27 }
我们查看上面两个函数以传值作为函数返回值和传引用作为函数返回值时的汇编有何不同,如下图:
我们不难发现传值返回的时候是把ret的值放入了eax寄存器中,而传引用返回的时候是把ret的地址放进了eax寄存器中。
因此我们应该在使用引用作为函数的返回值的时候应该注意:
1.不要返回⼀个临时变量的引⽤。
2. 如果返回对象出了当前函数的作⽤域依旧存在,则最好使⽤引⽤返回,因为这样更⾼效
在C语言中有指针,而C++中有应用,那么指针与引用究竟有什么区别与联系呢?
1. 引⽤只能在定义时初始化⼀次,之后不能改变指向其它变量(从⼀⽽终);指
针变量的值可变。
2. 引⽤必须指向有效的变量,指针可以为空。
3. sizeof指针对象和引⽤对象的意义不⼀样。 sizeof引⽤得到的是所指向的变量的
⼤⼩,⽽sizeof指针是对象地址的⼤⼩。
4. 指针和引⽤⾃增(++)⾃减(--)意义不⼀样。
5. 相对⽽⾔,引⽤⽐指针更安全。
所以在使用指针和引用的时候我们应该知道指针虽然⽐引⽤更灵活,但是也更危险。使⽤指针时⼀定要注意检查指针是否为空。指
针所指的地址释放以后最好置0,否则可能存在野指针问题。