本质:给变量起别名
语法:数据类型 &别名 = 原名
特点:传引用比传值的效率高很多
注意事项:
- 引用必须初始化,且初始化不能为空。
- 引用不能改变引用关系(引用的底层是指针常量(type * const pointer)),指针常量不可修改
- 引用不占内存,函数传参时,利用引用的技术让实参和形参代表的时同一块内存空间(可以简化指针修改实参)
- 引用可以作为函数的参数和返回值存在,但是不能返回局部对象的引用,变量前加static可接收,因为静态局部变量不会随着函数的结束而释放。
- 引用不要返回函数内部用new初始化的指针的引用,因为可能会造成内存泄漏
分类:
引用分为左值引用,右值引用,万能引用。其中,左值引用只能接收左值,右值引用只能接收右值,万能引用都可以接收。
左值是有名字能找到地址的变量。右值是没有名字找不到地址的变量,匿名对象(只存在于当前行,下一行就会被释放掉)和常量都是右值。万能引用是在左值引用前加const。
【注】:通常情况一个函数的返回值为右值,如果想返回左值的话要以引用的方式 int & dun(){};
使用场景
- 函数传参(const修饰形参,防止形参改变实参)
- 函数返回值
参数传递有两种
- 值传递
void test01(int a, int b)//值传递不修改原参数的值
{int c = a;a = b;b = c;
}
- 引用传递
void test02(int &a, int &b)
{int c = a;a = b;b = c;
}
【不能返回局部变量的引用 示例】:
int & fun()
{int a = 10;//局部变量return a;
}
int main()
{int& aaa = fun();cout << aaa << endl;//正常会输出随机值,因为函数结束a被释放掉//会输出10的原因:未来得及将a释放掉编译器先输出了cout << aaa << endl;//随机值return 0;
}
【左值引用 右值引用 万能引用】:
//返回静态变量引用
int& test02() {static int a = 20;return a;
}int main() {int&& R = 2;//右值引用接收右值int a = 2;int& R1 = a; //左值引用只能接收左值//int &&R2 = a; //报错//int &R3 = 2; //报错//万能引用:前面用const 修饰const int& R4 = 2;const int&& R5 = 3;//如果函数做左值,那么必须返回引用int &ref2 = test02();cout << "ref2 = " << ref2 << endl;cout << "ref2 = " << ref2 << endl;test02() = 1000;cout << "ref2 = " << ref2 << endl;cout << "ref2 = " << ref2 << endl;return 0;
}
匿名对象(右值)
- 没有名字的对象
- 只存在于当前行,到下一行就被释放掉了
- 函数以引用方式返回的值是左值 不引用返回的是匿名对象
引用和指针
- 都可以修改目标对象的值
- 都可以用于传递函数参数
- 引用必须在生命时初始化,指针可以随时初始化
引用不能返回局部变量的的原因?
- 局部变量的生命周期在函数返回后结束。如果返回局部对象的引用,实际上在函数调用者使用之前局部对象已经被销毁了。
- 但是引用的生命周期会延续到调用的上下文环境中。这样就出现了一个引用指向的内存已经被释放的非法引用。使用这个无效的引用可能会导致程序崩溃或其他难以预料的后果。