1.3. 引用使用场景?🚀?
1.3.1. 做参数?🚀?
1. 输出型参数(比如熟悉的returnSize,可以用引用去接受,传实参的时候不用地址了)
2. 减少拷贝,提升效率(用引用接受就是实参的别名,没有开空间,就和传指针差不多的去理解)
1.3.2. 做返回值?🚀?
传值返回:会有一个拷贝
?但是为什么要产生临时变量呢?
因为并不是都会像我们这样产生一个静态的局部变量然后去返回,而且确实静态变量在实际中是很少用的,因为会产生一些线程安全的问题,要加锁很麻烦。实际中是很可能不是静态变量的,是局部变量,我们之前是学过了函数栈帧,也知道返回值是存储在寄存器的,如果现在没有那个寄存器且返回局部变量,因为我们已经出了函数栈帧,函数栈帧销毁了,也就是那个局部变量已经销毁了,所以ret就得不到要返回的值,所以编译器为了不考虑是静态变量还是局部变量,就都产生了一个临时变量去存储。(如果数据大的话其实是会在上一层函数提前开辟好空间,然后互相拷贝,了解一下就可以了)?
证明是用一个临时变量存储的:
?加上const就不报错了 ,上面的那个图就是哈
传引用返回:没有这个拷贝了,函数返回直接就是返回变量的别名
证明ret是n的别名(这里去了static,去不去一样的哈对于这个结果):
这里ret和n的地址是一样的,说明ret是n的别名?
上面去掉static的虽然编译能过但是是不合法的(不安全)
我们来看看下面代码
(上面是cout.operator()函数,写错了)
其实也可以这么理解,取的值是上一次函数调用开辟函数栈帧的结构,注意!是先传参后开辟栈帧(静态的就没有这些问题哈,因为覆盖不了了)
上面的不安全:就是值可能会变,但是如果用static就没有问题
其实总的来说:
如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已
经还给系统了,则必须使用传值返回。
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行左右)