| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Python知识库 -> C++重温笔记(三): C++的引用竟然也有点深不可测 -> 正文阅读 |
|
[Python知识库]C++重温笔记(三): C++的引用竟然也有点深不可测 |
1. 写在前面c++在线编译工具,可快速进行实验: https://www.dooccn.com/cpp/ 这段时间打算重新把c++捡起来, 实习给我的一个体会就是算法工程师是去解决实际问题的,所以呢,不能被算法或者工程局限住,应时刻提高解决问题的能力,在这个过程中,我发现cpp很重要, 正好这段时间也在接触些c++开发相关的任务,所有想借这个机会把c++重新学习一遍。 在推荐领域, 目前我接触到的算法模型方面主要是基于Python, 而线上的服务全是c++(算法侧, 业务那边基本上用go),我们所谓的模型,也一般是训练好部署上线然后提供接口而已。所以现在也终于知道,为啥只单纯熟悉Python不太行了, cpp,才是yyds。 和python一样, 这个系列是重温,依然不会整理太基础性的东西,更像是查缺补漏, 不过,c++对我来说, 已经5年没有用过了, 这个缺很大, 也差不多相当重学了, 所以接下来的时间, 重温一遍啦 😉 资料参考主要是C语言中文网和光城哥写的C++教程,然后再加自己的理解和编程实验作为辅助,加深印象。 这篇文章主要是c++的引用,这个C语言里面也是没有的, 正好是刚回到学校, 作为缓冲,就少整理点, 赶的刚刚好, 哈哈。 主要内容:
Ok, let’s go! 2. C++引用初识函数调用时,对于参数的传递本质上是一次赋值的过程, 所谓赋值,就是对内存进行拷贝,而拷贝,就是将一块内存上的数据复制到另一块内存上。 对于基本类型(语言本身支持,like char, int, float)的数据,它们占用的内存往往只有几个字节,上面这个过程会很快, 而对于复杂类型(数组,结构体,类等由基本类型组合而成),对象是一系列数据的集合,数据数量无限制,这时候,对它们频繁拷贝可能消耗很多时间,效率变低。 所以C/C++禁止在函数调用的时候,直接传递数组的内容,而是强制传递数组指针, 但是呢? 对于结构体和对象并没有这种限制,可以是内容,也可以是指针,为了提高效率,在C语言里面,建议使用结构体指针( 引用是C++对C语言的一大扩充, 引用可以看做是数据的一个别名, 这个类似Windows的快捷方式,或者人的绰号。语法如下:
type是被引用的数据的类型,name是引用的名称,data是被引用的数据。 引用必须在定义的时候同时初始化,并且以后也要从一而终,不能再引用其他数据,有点类似于常量。 另外还要注意, 引用在定义的时候需要加 看个例子:
如果不希望通过引用修改原始数据, 可以在定义时加const限制
2.1 C++引用作为函数参数定义或声明函数时,可以将函数的形参指定为引用的形式,这样在调用函数时就会将实参和形参绑定在一起,让它们指代同一份数据。 如果在函数体修改了形参的数据, 那么实参的数据也会被修改,达到"函数内部影响函数外部"的效果。 比如,在学习C++时候常用的那个经典案例:
这三种交换的方式,后面两种可以真正达到交换的目的。
相比来看,第三种方式会更加直观。 2.2 C++引用作为函数返回值引用除了可以作为函数形参,还可以作为函数返回值。
上面要注意一个问题,就是返回的时候,不能返回局部数据(变量,对象,数组等),因为当函数调用完后局部数据会被销毁,有可能下次使用时数据就不存在。比如:
3. C++引用的本质引用是对指针的简单封装,底层依然是通过指针实现,引用占用的内存和指针占用的内存长度一样,在32位环境下是4个字节,64位环境下8个字节,但由于编译器内部的转换缘故,没法获取引用本身的地址,但引用是会占用内存的。 下面的栗子:
编译的时候,会被转换成下面的样子:
使用 引用的好处是让代码写的更加简洁, 比指针更加易用,但其背后还是指针。但这俩哥们之间有什么区别呢?
4. C++引用不能绑定到没法寻址数据4.1 临时数据这个概念得先从指针的角度去看, 指针就是数据或代码在内存中的地址, 指针变量指向的就是内存中的数据或者代码。 注意这里的内存, 指针只能指向内存,不能指向寄存器或者硬盘。因为寄存器和硬盘没有办法寻址。
比如:
上面这些表达式的结果以及函数返回值的结果都是放到寄存器中,所以尝试用 那么什么样的临时数据会放到寄存器里面呢? 盘点下:
看下面这个代码:
上面这个代码是没有问题的,也证明了结构体类型的临时数据被放到了内存里面。 4.2 常量表达式不包含变量的表达式称为常量表达式,比如100, 200+34, 1*2等。 常量表达式由于不包含变量,无不稳定因素,所以在编译阶段就能求值。 编译器不会单独分配内存来存储常量表达式的值,而是将常量表达式和代码合并到一起,放到虚拟空间代码区。
所以,常量表达式的值虽然在内存,但没有办法寻址,也不能用
4.3 引用也不能指代临时数据引用的本质就是指针,所以无法寻址的临时数据, 引用同样也不能绑定,并且C++对引用要求更严格,在某些编译器下,连放在内存中的临时遍历数据都不能指代。
当引用作为函数参数的时候,很容易给它传递临时数据, 下面的使用一定要注意:
判断是否是奇数的函数参数是引用类型,只能传递变量,不能是常量或者表达式。 其实更加标准的写法是值传递,而不用引用传递。
这样就没有问题了。 5. const引用创建临时变量引用不能绑定到临时数据, 但是有一种情况是例外的,就是使用const关键字对引用加以限定,引用就可以绑定到临时数据了。
还是这段代码,加了const之后, 编译就没有问题了。这是因为将常引用绑定到临时数据,编译器采取了一种妥协机制: 编译器会为临时数据创建一个新的,无名的临时变量,并将临时数据放入该临时变量中,然后再将引用绑定到该临时变量, 此时,其实也是引用绑定到了临时变量里面,临时变量是会被分配内存的。 那么,这时候,可能就会有一个疑问了,为啥,编译器对于常引用,就创建个临时变量,然后绑定, 而对于普通引用,就不创建临时变量呢?
简单的说,常引用不能修改数据,只能读,此时不会产生数据不一致性,而普通引用,如果建立了临时变量,那么通过引用只会修改到临时变量的值,而不会改到原值,此时会产生数据不一致性, 所以编译器考虑的很周到, 只有在必要时才会创建临时变量。
这个代码就是正确的了。 所以对于之前的代码,两种改法:值传递和const 引用。 6. C++ const引用与转换类型6.1 类型转换依然先从指针说起不同类型数据占用内存数量不一样,处理方式不一样,指针的类型要与它指向的数据类型严格对应。 下面这些是错误的:
尽管int可以自动转换成
这时候如果类型转换出现截断的时候,往往就会出现问题,而这种问题,往往我们是不太容易发现。 比如下面这个:
强行让 类比到引用,这个是一样的道理:
6.2 加上const呢?类型严格一致,对于普通引用,那必须遵守,但是加上const限定后,情况又发生变化, 编译器允许const引用绑定到类型不一致的数据。
why? 这背后依然是临时变量在发挥着作用。 当引用类型和数据类型不一致的时候,如果类型相近,且遵守类型的自动转换,此时编译器会创建一个临时变量,并将数据赋值给临时变量(这时候自动发生类型转换), 然后将const 引用绑定到临时变量。 这个和const引用绑定到临时数据采用方案是一样的。 注意,临时变量的类型和引用的类型是一样的,在将数据赋值给临时变量时会发生自动类型转换.
这个和我们想的就一样了, 这个其实,先为f创建一个int型的临时变量,这时候就是12, 然后再把int型的引用变量r给到int型的临时变量。但是当引用的类型和数据类型不遵守数据类型自动转换,编译器会报错。
小总:,给引用添加 const 限定后,不但可以将引用绑定到临时数据,还可以将引用绑定到类型相近的数据,这使得引用更加灵活和通用,它们背后的机制都是临时变量。 所以,我发现很多比较规范的代码都有这样的一个习惯: 引用类型的函数形参都一般加const修饰, 现在也差不多知道了原因。
下面的例子,演示了const引用的灵活性:
概括起来, 引用类型的形参加const限制的理由有3个:
在大的开发项目中,我也发现他们写函数形参的时候,也往往喜欢加const修饰,原来背后的原因是这啊。 学习到了哈哈。 这篇文章就整理到这里了,由于刚回到学校, c++这块先简单整理点作为缓冲,大部分内容是来自上面链接的第一篇文章,只摘取了我不知道的一些知识, 如果想系统学习,可以去上面链接里面去看啦。 接下来,利用10月份的这段时间,打算把c++的基础知识突击完毕啦,这个系列恢复更新, 其他系列,像推荐模型,西瓜书重温等,也同样恢复更新,不过,那俩由于是知识串联和白话解读,可能会慢很多,但也会坚持更新的频率,回学校就要开始好好学习,天天向上了 😉 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 17:47:41- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |