引用(C++11)
-
概念理解:
引用不是新定义的一个变量,而是对已经存在变量的别名
从内存上来看,编译器不会为引用开辟存储空间,引用与其所指向的变量共用同一块内存空间
通过下面一个示例代码来说明:
-
引用的应用:
首先要清楚引用的特性:
1,引用必须要初始化
2,引用类型必须与实体类型保持一致
3,一个变量可以有多个引用
4,引用一旦引用一个实体之后,不能再引用其他实体
常引用:
根据错误3:无法用“double”类型的值初始化“int &”类型的引用,
解决:可以加const 类型转换过程中存在临时变量空间,临时空间存储double转化为int类型的临时变量,const常引用指向临时变量空间
引用作为函数参数:
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(int* left, int* right)
{
int temp = left;
left = right;
right = temp;
}
引用作为函数参数,在swap交换函数中,如果单纯的值传递作为函数形参,函数调用结束后,发生交换后的数被销毁,难以将产生交换的值返回,在没有接触引用之前,采用指针变量,传地址作为函数形参,以此交换地址空间,即使调用结束,内存空间地址发生交换
具体调试过程如下:
引用作为函数返回值
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main() {
int& ret = Add(1, 2);
Add(3, 4);
printf("Add(1, 2) is %d:" ,ret );
return 0;
}
测试结果为7,为什么会是7?
以下通过调试观察
注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回
-
传值和传引用效率比较:
#include<iostream>
using namespace std;
#include <time.h>
struct A
{
int a[10000];
};
A a; // 值返回
A TestFunc1() {
return a;
} // 引用返回
A& TestFunc2(){
return a;
}
void TestReturnByRefOrValue() { // 以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 计算两个函数运算完成之后的时间
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
int main()
{
TestReturnByRefOrValue();
return 0;
}
-
引用和指针的区别:
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间
在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
int main() {
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
通过调试反汇编代码发现,二者在底层实现过程基本相同
但二者仅仅是在底层实现上类似,二者依然存在一定的区别,否则C++11标准下对引用的提出将毫无意义
引用和指针的不同点:
1. 引用在定义时必须初始化,指针没有要求
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型 实体
3. 没有NULL引用,但有NULL指针 ,可以free指针,不可以free引用
4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占 4个字节)
5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6. 有多级指针,但是没有多级引用
7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全
9.引用本身是有空间的,空间大小与指针大小相同,不会去开辟指向实体空间的大小
10.引用++ -->实体值++ 指针++ -->地址偏移