当前位置: 首页 > news >正文

C++学习——内联、C++11中的auto、for循环、nullptr

目录

文章目录

前言

一、内联函数

1.1内联函数的含义

1.2内联函数的使用模版

1.3宏定义与内联函数的区别

1.4内联函数的特性

二、C++11中的auto关键字

2.1auto简介

2.2for语法糖

三、空指针(nullptr)C++11


前言

这篇文章也是开胃菜,讲述的是关于内联函数的使用以及一些特点,auto关键字的使用(一般是与for循一起使用,它们两个就一起讲),还有一个nullptr空指针的理解。


一、内联函数

1.1内联函数的含义

内联函数的关键字是inline,通过inline就可以直接给当前的类的成员函数赋予内联的性质,编译的时候C++编译器会在使用内联函数的地方展开,没有函数调用占用线帧的开销,我们知道一般函数调用,都会在栈帧上开辟一块地方,内联函数的出现说白了就是提升了程序运行的效率。

1.2内联函数的使用模版

inline int Add(int x, int y)
{//代码部分
}

其实还是很简单的,把inline这个单词记住就可以了。

1.3宏定义与内联函数的区别

我们可以用一段程序来进行理解,假如我们需要输出一千次数字,我们给出了这个函数,也就是返回一个数:

int Add(int x, int y)
{return (x + y) * 10;
}

我们假如要使用这个,其实只需要调用这个函数就可以了,但是这里为了解释内联函数与宏定义。如果用宏定义来写的话:

#define Add(x,y) (x+y)*10

在函数体中调用该函数:

int main()
{for (int i = 0; i < 1000; i++){cout << Add(i, i + 1) << endl;}return 0;
}

这里是输出一千次的数字,可以正常的输出来。但是,宏定义有优点,有缺点,容易发生错误,首先,当我们在写宏定义的时候,也就是define的时候,容易出错。下面举一个例子。

我们要通过宏定义实现一个两个数相乘的逻辑,我们可以这么写:

#define MUL(x,y) x*y

我们通过主函数来测试一下:

int main()
{int x = 2 + 3;int y = 2;int z = MUL(x, y);cout << z << endl;return 0;
}

输出结果: 10

这里是正确的,但有有些时候要注意宏参数若包含运算符或表达式,建议用括号包裹以避免优先级问题,正常的写法是:

#define MUL(x,y) (x)*(y)

这样此案避免错误。

优点--宏函数不需要建立栈帧,提高调用效率

缺点--复杂,容易出错,可读性差,不能调试

在C++中就使用内联函数,内联函数不需要建立栈帧,不复杂,不容易出错,可读性好,可以调试,基本上算的是把宏定义的坑全部填上了。宏函数或者内联函数适用于短小的频繁调用的函数,
所有的函数不能变成内联函数,会把可编译程序变大,导致代码膨胀,因为内联函数的底层其实就是把这一块的代码段展开了,放到了编译代码中,如果过长的话就会发生代码膨胀。

注意:其实当前的大多数编译器会自动识别是否是用内联函数,有些函数即使你加了inline,编译器也不一定采纳你的建议,也会自己否决掉,声明中用内联函数调用的时候编译可以过,但生成不了,内联函数是不会进入符号表,没有地址,链接的时候就找不到,不需要call,声明展开啥也没有,这里只需要不让声明和定义分离就可以,直接展开后就不需要链接了,直接定义在.h文件中就可以。

1.4内联函数的特性

1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用。

缺陷:可能会使目标文件变大

优势:少了调用开销,提高程序运行效率。

2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。

3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址

了,链接就会找不到

总而言之,内联与宏定义都是用来提升性能的。

二、C++11中的auto关键字

2.1auto简介

早期的时候,auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但在c++11中的时候,给了新的含义,它不再是一个存储类型的标识符,而是作为一个新的指示符来指示编译器,auto声明的变量必须由编译器在编译时期而得。在编译的时候,auto会自动变成变量的实际的类型:

int main()
{int a = 1;float b = 2.0;auto c = a;auto d = c;auto e = b;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;cout << typeid(e).name() << endl;return 0;}

运行结果:

这里输出的是c,d,e的类型,所以auto是可以自动变成变量的实际的类型。

2.2for语法糖

其实auto最多的时候是和for循环使用,这个是c++中的一个语法糖。

正常我们在写一个循环的时候,for里面通常需要写三个参数,初始化、循环截止条件、表达式操作。这样有没有感觉非常的麻烦:

例如下面的代码:

int main()
{int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };for (int i = 0; i < 10; i++){cout << "i==" << arr[i] << endl;}return 0;
}

这段代码是通过一个简单的循环来输出数组里的数字,当我们使用auto来进行读操作的时候,就可以:

int main()
{int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };for (auto i : arr){cout << "i==" << i << endl;}return 0;
}

省略了很多,同时我们也可以用auto来进行修改元素,但是这里需要再变量前加上引用,表示是当前元素的别名,地址一样,修改这个就相当于修改原值了:

int main()
{int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };for (auto&i : arr){i ++;cout << "i==" << i << endl;}return 0;
}

我们运行出来每一个元素实现了修改(都加加):

还有很多地方auto可以进行使用,auto 的主要目的是减少冗余的类型声明,尤其是在复杂类型或模板编程中。

三、空指针(nullptr)C++11

在良好的编程习惯中,我们在声明一个变量的时候,通常会给值,但是没有值的时候,我们通常会给上一个NULL空指针,避免内存泄漏,如果一个指针没有一个明确的指向,那么后果是不堪设想的,谁知道会指向哪里,而且相当不安全。

正常都是这么写的:

void TestPtr()
{
int* p1 = NULL;
int* p2 = 0;
}

NULL实际是一个宏,在传统的C头文件(stddef.h)中。在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。

注意:

1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的

2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。

3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

http://www.dtcms.com/a/292315.html

相关文章:

  • Windows Cmake Vs2017/2010 编译安装Protobuf
  • 【计算机网络】第五章:传输层
  • 双向链表详解及实现
  • 解锁高品质音频体验:探索音频质量评估与测试的科学之道
  • Vibe Coding:人工智能 + 语音 = 新型开发者工作流
  • Thingsboard是什么?跟LoRaWAN 是什么关系?
  • 图像基础:从像素到 OpenCV 的入门指南
  • 【加解密与C】Rot系列(四)RotSpecial
  • 【windows修复】解决windows10,没有【相机] 功能问题
  • 2025易支付插件/度小满/拉卡拉缴费易/嘉联/海科码钱/富友 支付量身定制的易支付插件优化方案
  • Jupyter Notebook |使用清华源下载安装
  • Final_基于时序数据的回归预测
  • ABP VNext + FluentMigrator:数据库迁移管理
  • AI智能体“上下文工程”实践:来自 Manus 项目的经验总结
  • 【ArcGIS Pro】设置临时存储文件夹(计算缓存数据存放位置)
  • RedisJSON 指令精讲JSON.STRLEN 高效统计字符串长度
  • OpenMVG OpenMVS 安装全流程常见问题与解决方法总结
  • almalinux9.6系统-基础环境准备
  • 【大气反演模型CIF第二期】通过 Docker 容器快速部署和运行 CIF 系统
  • 基于eBPF的Kubernetes网络故障自愈系统设计与实现
  • 33、基于JDK17的GC调优策略
  • Hyper-V虚拟化平台GPU分区和GPU半虚拟化技术比较及应用建议
  • Linux文件系统深入理解
  • repmgr+vip实现对业务透明的高可用切换
  • 数据库—修改某字段默认值
  • Oracle RAC+ADG switchover 切换演练流程
  • TDSQL
  • [08006][1033] ORA-01033: ORACLE 正在初始化或关闭--问题修复
  • 达梦数据库表字段增加时报错[-2106]:无效的表或视图名,[-2116]:列[IS_REPEAT]已存在
  • Python趣味算法:折半查找(二分查找)算法终极指南——原理、实现与优化