c++引用详细解说4

电子说

1.3w人已加入

描述

6、效率比较

值和引用的作为返回值类型的性能比较:

#includestruct 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;}

由于传值返回要拷贝,所以当拷贝量大,次数多时,比较耗费时间;而传引用返回就不会,因为返回的就是别名。

面向对象

对于返回函数作用域还在的情况,引用返回优先。

引用传参和传值传参效率比较 :

#includestruct 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++引用的一个详细解读,希望大家受益良多哈。平时在写代码的时候多调试看看里面的原理,看看编译器到底是怎么进行运行的,让自己对编码这块更具有灵性!

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分