内联函数:
内联函数 就是函数名前面以inline修饰的函数 编译时c++编译器会在调用内联函数的地方展开(篇幅小的函数才会展开 编译器会自动识别) 没有函数调用建立栈帧的开销。内联函数可以提升程序运行的效率 所以我们经常调用的小函数就适合
这个替换的机制是不是和C语言里面的 宏 很相似呢 但是他们两个是不相同的 就好像 我们的宏是不能够调试的 但是我们的内联函数可以调试的
大家觉得为什么c++要有一个这个内联函数呢? 首先我们的宏是替换 如果我们写得时候没有注意 优先级 那么是有可能出错的 大家学习宏的时候应该有所体会吧 但是我们自己写函数时容易出错嘛? 还有就是我们的内联函数的特性 是去把一个函数展开 不用开辟栈帧
默认的debug版本下不会展开 只有优化后的 或者 自己去调了设置的才会看到像下面这样的没有 call 的
大家看这里面就没有call指令了 不会去调用函数了
内联函数的特性:
inline是一种 空间换取时间 的做法,这样为我们省去了开辟栈帧的开销 当然也不是说我们内联函数哪里都可以适用,像对于我们的很长的代码或者你这个函数里面包含有递归的这些内联函数就不太适用了
其次,我们的inline对于编译器只是一个建议,编译器会自己判断、优化,像如果是上面那种不适用的情况,我们编译器就会忽略掉它的内联 大家来看:
篇幅小的会替换 大家来看篇幅大的:
大家看到篇幅大的它还会替换嘛 它是不是就是去调用call指令了
另外大家在使用inline的时候还一个要注意的点就是,我们的函数因为inline展开后,是没有函数地址的,所以大家在使用的时候,不要把 声明 定义 分离 因为这样的话后面程序在链接的时候就会出现链接不上的问题
我们的程序在执行的时候分为这么四个步骤 预处理->编译->汇编->链接 我们的汇编会利用编译期间实现过的符号汇总来进行一个 形成符号表的操作 如果有的符号没有地址的话 就是属于声明 和 定义分离了 只有声明是没有地址的 所以就会在链接的时候进行一个 符号表的合并和重定位(多个目标文件(.o)进行链接的时候会通过符号表查看来自外部的符号是否存在)
auto:
auto是一个新的类型指示符来指示编译器,auto声明的变量必须由该编译器在编译时期推导而得 意思就是它可以自动的去推导一个变量是什么类型
int a=10; auto b=a; auto c='d';
对于这个我们后面学习迭代器的时候用起来还是很方便的 就像那些类型名很长的这个就挺适用的
还有这样的场景:auto& auto* 这两个得意思是 我们表明了我们传过去得变量得是一个引用或者是指针
int a = 10; auto& = a; auto* = &a; auto* = a;
最下面得那种写法就是错误得 因为我们指定了传过去的得是一个指针
如果说在同一行声明多个变量时,这些必须得是相同得类型,因为这时我们得auto是先自动推导第一个变量的类型再拿推导出来的类型去定义以后的变量
auto a=1,b=2.0;
这样就是不对的
auto 还有一个应用场景: 就是我们的范围for
我们以前的for循环:for(int i=0;i<size;i++) 就好像是这样 我们的范围for是可以这样写的:
for(auto ch:arr) { //依次自动取arr中的数据,赋值给ch,会自动判断结束 }
虽说我们是依次把arr中的值赋值给ch 但ch始终是一个拷贝 我们是不能通过ch直接改变arr数组中的内容的
for(auto& ch:arr) { //取别名后 就可以直接改变arr数组里面的值了 }
有一个点大家要注意我们使用的数组的范围必须是固定的,不能是不确定的 大家看下面的代码我们传进来的参数是一个数组首元素的地址 哪怕是常规的for循环也是不能直接使用arr的
void test(int arr[]) { for(auto ch:arr) { ; } }
auto不适用的场景:
① auto不能作为函数的参数 因为在编译阶段会报错 编译器那时无法推导具体类型
auto也是不能做返回值的哦
② auto也不能用来声明一个数组
nullptr:
再c++11中 我们的NULL 和 0 是等价的 大家可以到stddef.h文件去看一下 而我们的nullptr就是为了弥补这个缺陷,好像我们平常同时使用 NULL 和 0 时系统就会使用最前面的那个了那我写在后面的 0 或 NULL 不就没有用了嘛,所以有了nullptr
所以我们在c++中表示一个空指针都是用的 nullptr