新手避坑指南:C++ 引用、内联函数与 nullptr 全解析
一、 引用1. 引用基础概念给已有的变量“新名字”别名使用类型引⽤别名引⽤对象;案例在需要传指针的地方可以用引用代替不需要调用该指针让形参就叫别名改变形参就是改变实参特性引用在定义的时候必须初始化一个变量可以有多个引用引用一旦引用一个实体再不能引用其他实体代码语言javascriptAI代码解释int a 10; int ra; // 编译报错“ra”: 必须初始化引⽤ int b a; int c 20; // 这⾥并⾮让b引⽤c因为C引⽤不能改变指向 // 这⾥是⼀个赋值主要应用函数参数传递函数返回值引用返回值能不能随便用2. 引用返回注意事项代码语言javascriptAI代码解释int func() { int a 0; return a;//错的:a是局部的返回时候已经销毁类似野指针 } int func1(int ra) { ra 3 return ra;//对的:ra是外部传入的引用出函数依旧存在 }3.const引用规则权限可缩小不可放大仅限制引用本身的访问权限代码语言javascriptAI代码解释int main() { const int a 0; int ra a;//错的 const int ra a;//对的 //权限放大 //注意分辨 const int a 0; int ra a;//这是可以的不是权限放大 int b 0; const int rb b;//对的 //权限缩小 //这个地方没有缩小b的权限b依旧能该改变 b;//对 rb;//错 //类比公共场合添加一个身份做不了一些事情权限缩小 int rc 30;//错 const int rc 30;//对 //const引用可以给常量取别名单纯的引用不可以 //这是因为const修饰的变量具有常性所以不可更改这也就是const修饰能够对常量取别名的原因 //编译器需要⼀个空间暂存表达式的求值结果中间值时临时创建的⼀个未命名的对象 int rd (ab);//可以对临时对象赋值 int rd (ab);//不可以对临时对象单纯引用没法修改 const int rd (ab);//可以用const引用不修改 //这也是因为临时对象具有常性 double d 12.34; int i d;//是隐式类型转换这个过程有临时对象 int i d;//不可以 const int i d;//可以 //下面介绍一个很好用的东西 //函数模板T可以是任意类型 template class T void func(T val) { //注意看这里传入的T是任意类型 //所以程序员对它进行一个引用T val防止传入的值太大拷贝成本高 //这里传常量/临时对象/带有类型转换可以吗不行 //最终const T val,这样子就什么都能传 // 使用const引用可接收 // 1. 普通变量 // 2. 常量 // 3. 临时对象 // 4. 类型转换结果 // 类似void*的通用性 } return 0; }4. 指针和引用的关系与区别引用不额外开空间指针是开一个空间来存储地址引用使用必须初始化指针不是必须要求的引用只能初始化一次不能更改指针可以更改指向对象引用可以直接访问对象别名指针需要解引用。sizeof引用返回的是引用类型的大小而指针则根据操作系统不一样大小不一样指针有野指针和空指针的问题引用很少有代码语言javascriptAI代码解释int* ptr nullptr; int rptr *ptr; rptr;在这里插入图片描述二、inline 和 宏函数1. 宏函数在C语言里有通过#define定义的宏函数为了防止宏函数的使用往往小心翼翼要加很多层括号本质预编译阶段的文本替换不是真正的函数调用。目的在避免函数调用栈帧开销的同时实现代码复用比普通函数更轻量比内联函数更「强制」替换。展示:代码语言javascriptAI代码解释//正确 #define ADD(a,b) ((a)(b)) int main() { int add ADD(3,2); return 0; } //错误加分号 #define ADD(a,b) ((a)(b)); int main() { if (ADD(3, 2) 0) { //执行某操作 } return 0; } #define ADD(a,b) (ab) //错误不加内层括号 int main() { int add ADD(1 ^ 1, 2 ^ 2); //替换以后 》1^(12)^2 return; } #define ADD(a,b) (a)(b); //错误外层无括号 int main() { int add ADD(3,2) * ADD(3,2); //替换以后 》3(2*3)2 return 0; }以上是宏函数的使用2. inline内联函数上面宏函数的二条提到了内联函数inline是一个关键字他所修饰的函数称之为内联函数上文提到宏函数是为减少函数栈帧的开销inline也有这个作用内联函数有什么用 内联函数是一个类似”宏函数“的函数不同于宏函数内联函数是在函数内部计算以后返回值有的朋友要说函数不都这样吗其实不然内联函数的本质是把函数的独立栈帧省略掉直接使用调用者的栈帧。 这里插入栈帧的概念栈帧也叫「活动记录」是程序运行时栈内存中为单个函数调用分配的一块独立内存区域用于存储该函数的局部变量函数参数返回地址函数执行完后要回到调用者的哪一行代码栈基址EBP/RBP 寄存器用于定位栈帧内的变量临时数据比如表达式计算的中间结果程序的调用栈Call Stack就是由多个嵌套的栈帧组成的比如main() 调用funcA()funcA() 又调用funcB()栈中会依次压入main栈帧 →funcA栈帧 →funcB栈帧栈顶。比如说在main函数中调用一个inline int add的函数如果去掉inline他会创建栈帧而加上inline变为内联函数以后就在main函数的栈帧上创建自己的栈帧省去了跳转等操作简单了许多当函数 A 调用函数 B 时函数 A 是「调用者Caller」它的栈帧就是「调用者的栈帧」函数 B 是「被调用者Callee」它的栈帧就是「被调用者的栈帧」。 「调用者的栈帧」就是发起调用的那个函数在栈上的内存区域在函数调用过程中它会暂时被「被调用者的栈帧」覆盖栈顶偏移但调用结束后CPU 会回到调用者的栈帧继续执行。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2571542.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!