> 文档中心 > C++引用与内联函数inline

C++引用与内联函数inline

目录

1. 引用 🚀 

1.1. 理论 🚀

1.1.1 定义 🚀 

1.1.2. 用法 🚀 

1.1.3. 引用特性 🚀 

1.2. 代码深度理解 🚀 

1.2.1. 权限讲解 🚀 

1.2.2. 权限深度理解 🚀 

1.3. 引用使用场景 🚀 

1.3.1. 做参数 🚀 

1.3.2. 做返回值 🚀 

1.4. 引用和指针的区别 🚀 

2. 内联函数 🚀 

2.1. 概念 🚀 

2.2. 实用 🚀 

2.2 关于宏和C++的优化 🚀 


C语言入门篇进阶篇深剖篇都整理在这里了哈。然后这里是个人主页,比点头像更好找文章哈。


作者和朋友建立的社区:非科班转码社区-CSDN社区云💖💛💙

期待hxd的支持哈🎉 🎉 🎉


最后是打鸡血环节:你只管努力,剩下的交给天意🚀 🚀 🚀 

1. 引用 🚀 

1.1. 理论 🚀

1.1.1 定义 🚀 

引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

1.1.2. 用法 🚀 

类型& 引用变量名(对象名) = 引用实体;

比如   int& b=a;

这里b就是a的引用(别名)

1.1.3. 引用特性 🚀 

1. 引用在 定义时必须初始化 2. 一个变量可以有多个引用(可以引用常量) 3. 引用一旦引用一个实体,再不能引用其他实体

1.2. 代码深度理解 🚀 

1.2.1. 权限讲解 🚀 

1.2.2. 权限深度理解 🚀 

但是对于为什么int b =a 不加const是因为这是赋值,b的改变不影响a

而且现在c是这个临时变量的别名,不是b的了

1.3. 引用使用场景 🚀 

1.3.1. 做参数 🚀 

1. 输出型参数(比如熟悉的returnSize,可以用引用去接受,传实参的时候不用地址了)

2. 减少拷贝,提升效率(用引用接受就是实参的别名,没有开空间,就和传指针差不多的去理解)

1.3.2. 做返回值 🚀 

传值返回:会有一个拷贝

 但是为什么要产生临时变量呢?
因为并不是都会像我们这样产生一个静态的局部变量然后去返回,而且确实静态变量在实际中是很少用的,因为会产生一些线程安全的问题,要加锁很麻烦。实际中是很可能不是静态变量的,是局部变量,我们之前是学过了函数栈帧,也知道返回值是存储在寄存器的,如果现在没有那个寄存器且返回局部变量,因为我们已经出了函数栈帧,函数栈帧销毁了,也就是那个局部变量已经销毁了,所以ret就得不到要返回的值,所以编译器为了不考虑是静态变量还是局部变量,就产生了一个临时变量去存储。(如果数据大的话其实是会在上一层函数提前开辟好空间,然后互相拷贝,了解一下就可以了) 

证明是用一个临时变量存储的:

 加上const就不报错了 ,上面的那个图就是哈

传引用返回:没有这个拷贝了,函数返回直接就是返回变量的别名

证明ret是n的别名(这里去了static,去不去一样的哈对于这个结果):

这里ret和n的地址是一样的,说明ret是n的别名 

上面去掉static的虽然编译能过但是是不合法的(不安全)

我们来看看下面代码

(上面是cout.operator()函数,写错了)

其实也可以这么理解,取的值是上一次函数调用开辟函数栈帧的结构,注意!是先传参后开辟栈帧(静态的就没有这些问题哈,因为覆盖不了了)

上面的不安全:就是值可能会变,但是如果用static就没有问题

其实总的来说:

如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已 经还给系统了,则必须使用传值返回。

1.4. 引用和指针的区别 🚀 

语法概念上 引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。 底层实现上 实际是有空间的,因为 引用是按照指针方式来实现 的。

引用和指针的不同点: 

1. 引用 在定义时 必须初始化 ,指针没有要求 2. 引用 在初始化时引用一个实体后,就 不能再引用其他实体 ,而指针可以在任何时候指向任何一个同类型实体 3. 没有 NULL 引用 ,但有 NULL 指针 4. sizeof 中含义不同 引用 结果为 引用类型的大小 ,但 指针 始终是 地址空间所占字节个数 (32 位平台下占4个字节 ) 5. 引用自加即引用的实体增加 1 ,指针自加即指针向后偏移一个类型的大小 6. 有多级指针,但是没有多级引用 7. 访问实体方式不同, 指针需要显式解引用,引用编译器自己处理 8. 引用比指针使用起来相对更安全

2. 内联函数 🚀 

2.1. 概念 🚀 

1. 以 inline 修饰 的函数叫做内联函数, 编译时 C++ 编译器会在 调用内联函数的地方展开 ,没有函数压栈的开销,内联函数提升程序运行的效率。(和c的#define有点像) 2.  inline 对于编译器而言只是一个建议 ,编译器会自动优化,如果定义为 inline 的函数体内有循环 / 递归等 等,编译器优化时会忽略掉内联。 3. inline 不建议声明和定义分离,分离会导致链接错误。因为 inline 被展开,就没有函数地址了,链接就会找不到。

2.2. 实用 🚀 

为什么C++会出内联函数呢,其实就是为了解决宏函数晦涩难懂,容易写错的问题,而且宏不支持调试。而inline就是解决这些哈。 当我们函数较小而调用次数较多

 

这样就会开辟大量重复的函数栈帧(有call就是有函数调用,开辟函数栈帧)

内联函数就会把调用的地方像宏一样展开(汇编指令),这样就大量减少了函数栈帧的开辟。

但是我们这里虽然用了inline但是还是有call是因为

inline默认的debug是不会展开(有call),要release或者优化,优化了就进不去了,因为没有栈帧了

解释:

如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。  

查看方式: 1. release 模式下,查看编译器生成的汇编代码中是否存在 call Add 2. debug 模式下,需要对编译器进行设置,否则不会展开 ( 因为 debug 模式下,编译器默认不会对代码进行优化,以下给出vs2022 的设置方式 )

现在反汇编就看不到call了哈 

对于编译器内联是一种建议,如果代码过长就不会接受我们的建议(一般是10行左右)

2.2 关于宏和C++的优化 🚀 

宏的优缺点? 优点: 1. 增强代码的复用性。 2. 提高性能。 缺点: 1. 不方便调试宏。(因为预编译阶段进行了替换) 2. 导致代码可读性差,可维护性差,容易误用。 3. 没有类型安全的检查 。 C++ 有哪些技术替代宏 1. 常量定义 换用 const 2. 函数定义 换用内联函数

最后的最后,创作不易,希望读者三连支持💖

赠人玫瑰,手有余香💖