6、效率比较
值和引用的作为返回值类型的性能比较:
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;
}
由于传值返回要拷贝,所以当拷贝量大,次数多时,比较耗费时间;而传引用返回就不会,因为返回的就是别名。
对于返回函数作用域还在的情况,引用返回优先。
引用传参和传值传参效率比较 :
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{
A a;
// 以值作为函数参数
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作为函数参数
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
TestRefAndValue();
}
还是引用快,因为引用减少拷贝次数:
总结:引用的作用主要体现在传参和传返回值
- 引用传参和传返回值,在有些场景下可以提高性能(大对象 and 深拷贝对象 – 之后会讲)。
- 引用传参和传返回值,在对于输出型参数和输出型返回值很舒服。说人话就是形参改变,实参也改变 or 返回对象(返回值改变)。
7、常引用
const 修饰的是常变量,不可修改。
a本身都不能修改,b为a的引用,那么b也不可以修改,这样就没意义了。a是只读,但是引用b具有可读可写的权利,该情况为权限放大,所以错误了。
这时,只要加 const 修饰 b ,让 b 的权限也只有只读,使得 权限不变 ,就没问题了:
而如果原先变量可读可写,但是别名用 const 修饰,也是可以的,这种情况为 权限缩小 :
对于函数的返回值来说,也不能权限放大,例如:
int fun()
{
static int n = 0;
n++;
return n;
}
int main()
{
int& ret = fun(); // error
return 0;
}
这样也是不行的,因为返回方式为 传值返回 ,返回的是临时变量,具有 常性 ,是不可改的;而引用放大了权限,所以是错误的;这时加 const 修饰就没问题:
const int& ret = c(1, 2)
那么这种情况为什么不可以?
而这样就可以了?
因为类型转换会产生临时变量 :
对于类型转换来说,在转换的过程中会产生一个个临时变量,例如 double d = i,把i转换后的值放到临时变量中,把临时变量给接收的值d
而临时变量具有常性,不可修改,引用就加了写权限,就错了,因为 权限被放大了 。
小结:对于引用,引用后的变量所具权限可以缩小或不变,但是不能放大(指针也适用这个说法)
作用 :在一些场景下,假设 x 是一个大对象,或者是深拷贝对象,那一般都会用引用传参,减少拷贝,如果函数中不改变 x ,尽量用 const 引用传参。
这样可以防止 x 被修改 ,而对于 const int& x 也可以接受权限对等或缩小的对象,甚至为常量:
结论 :const type& 可以接收各种类型的对象(变量、常量、隐式转换)。对于输出型参数用引用,否则用 const type&,更加安全。
8、指针和引用区别
从语法概念上来说,引用是没有开辟空间的,而指针是开辟了空间的,但是从底层实现上来说,则又不一样:
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
汇编:
lea 是取地址:我们发现无论引用和指针,都会取地址,且这些过程和指针一样。
其实从汇编上,引用其实是开空间的,并且实现方式和指针一样,引用其实也是用指针实现的。
区别汇总:
- 引用概念上定义一个变量的 别名 ,指针存储一个变量 地址。
- 引用 在定义时 必须初始化 ,指针最好初始化 ,但是不初始化也不会报错。
- 引用在初始化时引用一个实体后 ,就不能再引用其他实体 ,而指针可以在任何时候指向任何一个同类型。
- 没有NULL引用,但有NULL指针。
- 在sizeof中含义不同:引用结果为 引用类型的大小,但指针始终是 地址空间所占字节个数 (32位平台下占4个字节)。
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小。
- 有多级指针,但是没有多级引用。
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理。
- 引用比指针使用起来相对更安全。
以上全部是对c++引用的一个详细解读,希望大家受益良多哈。平时在写代码的时候多调试看看里面的原理,看看编译器到底是怎么进行运行的,让自己对编码这块更具有灵性!
-
C语言
+关注
关注
180文章
7597浏览量
136129 -
C++
+关注
关注
22文章
2104浏览量
73482 -
面向对象
+关注
关注
0文章
64浏览量
9978
发布评论请先 登录
相关推荐
评论