内联函数|auto关键字|范围for的语法|指针空值

news2024/11/18 16:41:28

文章目录

    • 一、内联函数
      • 1.1概念
      • 1.2特性
    • 二、auto关键字
      • 2.2类型别名思考
      • 2.3auto简介
      • 2.4auto使用细则
      • 2.4 auto不能推导的场景
    • 三、基于范围的for循环(C++11)
      • 3.1 范围for的语法
    • 四、指针空值nullptr(C++11)
      • 4.1 C++98中的指针空值

在这里插入图片描述
所属专栏:C++初阶

在这里插入图片描述

一、内联函数

1.1概念

inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,提高了运行效率
在这里插入图片描述

如果在上面Add函数添加了inline关键字修饰将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。

查看方式:

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

在这里插入图片描述

1.2特性

  1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。

比如Add函数有10行代码,调用1000次那么如果是普通函数的话需要的空间就是10+1000,如果是内联函数,需要的空间就是10*1000

  1. inline对于编译器而言只是一个建议不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。下图为《C++prime》第五版关于inline的建议:
    在这里插入图片描述

  2. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。(参考编译和链接)
    在这里插入图片描述
    在这里插入图片描述
    【面试题】
    宏的优缺点?
    优点:
    1.增强代码的复用性。
    2.提高性能。(宏函数是直接展开的,不需要调用建立函数栈帧,提高了效率)

    缺点:
    1.不方便调试宏。(因为预编译阶段进行了替换)
    2.导致代码可读性差,可维护性差容易误用。(宏函数的写法比较复杂,不容易掌握)
    3.没有类型安全的检查 。(宏函数都是直接展开的不会检查
    C++有哪些技术能够替代宏?

    1. 常量定义 换用const enum
    2. 短小函数定义 换用内联函数

二、auto关键字

2.2类型别名思考

  1. 类型难于拼写
  2. 含义不明确导致容易出错
#include <string>
#include <map>
int main()
{
 std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange", "橙子" }, 
 {"pear","梨"} };
 std::map<std::string, std::string>::iterator it = m.begin();
 while (it != m.end())
 {
 //....
 }
 return 0;
 }

std::map<std::string, std::string>::iterator是一个类型,但是该类型太长了,特别容易写错。这里可以用到auto简化

2.3auto简介

在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的是一直没有人去使用它,大家可思考下为什么?
C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

int TestAuto()
{
 return 10;
}
int main()
{
 int a = 10;
 auto b = a;
 auto c = 'a';
 auto d = TestAuto();
 
 cout << typeid(b).name() << endl;
 cout << typeid(c).name() << endl;
 cout << typeid(d).name() << endl;
 
 //auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
 return 0;
}

【注意】
使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

2.4auto使用细则

  1. auto与指针和引用结合起来使用
    用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
int main()
{
 int x = 10;
 auto a = &x;
 auto* b = &x;
 auto& c = x;
 cout << typeid(a).name() << endl;
 cout << typeid(b).name() << endl;
 cout << typeid(c).name() << endl;
 *a = 20;
 *b = 30;
 c = 40;
 return 0;
}
  1. 在同一行定义多个变量
    当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量
void TestAuto()
{
 auto a = 1, b = 2; 
 auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
 }

2.4 auto不能推导的场景

1. auto不能作为函数的参数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

2. auto不能直接用来声明数组

void TestAuto()
{
 int a[] = {1,2,3};
 auto b[] = {456};
}

3. 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
4. auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进行配合使用。

三、基于范围的for循环(C++11)

3.1 范围for的语法

在C++98中如果要遍历一个数组,可以按照以下方式进行:

void TestFor()
{
 int array[] = { 1, 2, 3, 4, 5 };
 for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
 array[i] *= 2;
 
 for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)
 cout << *p << endl;
}

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

//语法糖
void TestFor()
{
 int array[] = { 1, 2, 3, 4, 5 };
 for(auto& e : array)
 e *= 2;
 
 for(auto e : array)
 cout << e << " ";
 
 return 0;
}

自动依次取数组中的数据赋值给e对象,自动判断结束

四、指针空值nullptr(C++11)

4.1 C++98中的指针空值

在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下方式对其进行初始化:

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

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

可以看到,NULL可能被定义为字面常量0或者被定义为无类型指针(void)的常量*。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int)
{
 cout<<"f(int)"<<endl;
}
void f(int*)
{
 cout<<"f(int*)"<<endl;
}
int main()
{
 f(0);
 f(NULL);
 f((int*)NULL);
 return 0;
}

程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。
在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。
注意:
1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
2. 在C++11中,sizeof(nullptr) 与 sizeof((void)0)所占的字节数相同.
3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1501093.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

❤ Vue3项目使用yarn 搭建 Vue3+Pinia+Vant3/ElementPlus+typerscript 系统篇(一)

❤ Vue3 完整项目搭建 Vue3PiniaVant3/ElementPlustyperscript系统篇&#xff08;一&#xff09; 1、项目环境和简介 环境 使用nvm 版本 20.10.0 node 版本 20.10.0 npm版本 10.2.3 项目简介&#xff1a; Vue3全家桶viteTSPiniaVant3/ElementPlus-搭建Vue3.x项目 项目开源地…

【JAVA】优化if else的几种方式

在代码编写初期&#xff0c;我们写出来的代码&#xff0c;脉络清晰&#xff0c;结构简单。可随着bug或者新需求的出现&#xff0c;状态变得越来越多&#xff0c;只能不停地加else来区分&#xff0c;久而久之&#xff0c;判断的次数越来越多&#xff0c;嵌套的层数也越来越深&am…

Day 8.TCP包头和HTTP

TCP包头 1.序号&#xff1a;发送端发送数据包的编号 2.确认号&#xff1a;已经确认接收到的数据的编号&#xff08;只有当ACK为1时、确认号才有用&#xff09;&#xff1b; TCP为什么安全可靠 1.在通信前建立三次握手 SYP SYPACK ACK 2.在通信过程中通过序列号和确认号和…

python密码判断 2023年12月青少年编程电子学会python编程等级考试二级真题解析

目录 python密码判断 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python密码判断 2023年12月 python编程等级考试级编程题 一、题目要求 …

云函数-激活码列表-并发同时读取操作数据解决方案

业务场景 第三方平台创建并提供了激活码列表&#xff0c;每个激活码只能使用一次。并将数据导入数据库中&#xff0c;用户在某个业务场景下获取激活码&#xff0c;N个用户同时请求获取计划码时&#xff0c;会返回同一激活码。 //获取数据 await db_activeCode.where({isUse: t…

手写简易操作系统(一)--环境配置

本专栏是我新开设的一个学术专栏&#xff0c;旨在全面介绍手写操作系统的相关内容。其中包括实模式向保护模式的过渡、锁机制、信号量操作、内存分配、硬盘驱动、文件系统、简单shell和管道等操作系统核心知识。该专栏旨在为有意开发自己操作系统的研究人员提供指导与帮助。作为…

如何在Windows环境下编译OpenOCD

1. 安装Cygwin Windows环境下编译OpenOCD可以是在MinGW-w64/MSYS或Cygwin下&#xff0c;这里选择Cygwin&#xff0c;下载安装Cygwin。 2. 进入OpenOCD源代码目录 打开Cygwin&#xff0c;进入OpenOCD源代码目录&#xff0c;例如代码放在D:\Temp\OpenOCD\openocd-code下&#…

OpenHarmony教程指南-自定义通知推送

介绍 本示例主要展示了通知过滤回调管理的功能&#xff0c;使用ohos.notificationManager 接口&#xff0c;进行通知监听回调&#xff0c;决定应用通知是否发送。 效果预览 使用说明 1.在使用本应用时&#xff0c;需安装自定义通知角标应用&#xff1b; 2.在主界面&#xff…

【Web前端】Vue核心基础

文章目录 1. Vue简介2. Vue官网使用指南3. 初识Vue3.1 搭建Vue开发环境3.2 HelloWorld案例3.3 el与data的两种写法3.4 MVVM模型3.5 模板语法 4. 数据绑定4.1 v-bind单向数据绑定4.2 v-model双向数据绑定 5. 事件处理5.1 v-on绑定事件5.2 事件修饰符5.3 键盘事件 6. 计算属性6.1…

吴恩达机器学习-可选实验室:特征工程和多项式回归(Feature Engineering and Polynomial Regression)

文章目录 目标工具特征工程和多项式回归概述多项式特征选择功能备用视图扩展功能复杂的功能 恭喜! 目标 在本实验中&#xff0c;你将:探索特征工程和多项式回归&#xff0c;它们允许您使用线性回归的机制来拟合非常复杂&#xff0c;甚至非常非线性的函数。 工具 您将利用在以…

rabbitmq4

独占队列&#xff1a;我们的队列只能被当前通道所绑定&#xff0c;不能被其他的连接所绑定&#xff0c;如果有其他的通道或连接再使用此队列的话&#xff0c;会直接报错&#xff0c;一般设置为false&#xff1a; autoDelete&#xff1a;消费者在消费完队列&#xff0c;并且彻底…

[C语言]——分支和循环(4)

目录 一.随机数生成 1.rand 2.srand 3.time 4.设置随机数的范围 猜数字游戏实现 写⼀个猜数字游戏 游戏要求&#xff1a; &#xff08;1&#xff09;电脑自动生成1~100的随机数 &#xff08;2&#xff09;玩家猜数字&#xff0c;猜数字的过程中&#xff0c;根据猜测数据的⼤…

音视频学习笔记——c++多线程(一)

✊✊✊&#x1f308;大家好&#xff01;本篇文章主要整理了部分多线程相关的内容重点&#x1f607;。首先讲解了多进程和多线程并发的区别以及各自优缺点&#xff0c;之后讲解了Thead线程库的基本使用。 本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统…

Linux grep

文章目录 1. 基本用法2.字符转义3.二进制文件查找4.打印目标字段的附近行4. 多条件过滤5. 目录中过滤——用于在文件夹中筛选/排除指定后缀文件6.反向过滤——用于筛选7.只输出匹配内容——用于统计8. 筛选出包含字段的文件9.正则匹配10.管道和grep11.grep和wc/uniq/sort的合用…

在Vue中处理接口返回的二进制图片数据

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

解决方案TypeError: string indices must be integers

文章目录 一、现象&#xff1a;二、解决方案 一、现象&#xff1a; PyTorch深度学习框架&#xff0c;运行bert-mini&#xff0c;本地环境是torch1.4-gpu&#xff0c;发现报错显示&#xff1a;TypeError: string indices must be integers 后面报字符问题&#xff0c;百度过找…

goby的安装和使用

简介 Goby是一款基于网络空间测绘技术的新一代网络安全工具&#xff0c;它通过给目标网络建立完整的资产知识库&#xff0c;进行网络安全事件应急与漏洞应急。 Goby可提供最全面的资产识别&#xff0c;目前预置了超过10万种规则识别引擎&#xff0c;能够针对硬件设备和软件业…

程序员常用的几种算法

程序员常用的几种算法 一、程序员算法汇总二、程序员常用的几种算法1.选择排序算法1.1 选择排序算法解析&#xff1a;1.2 示例代码&#xff1a; 2.插入排序算法2.1 插入排序算法解析&#xff1a;2.2 示例代码&#xff1a; 3.冒泡排序算法3.1 冒泡排序算法解析&#xff1a;3.2 示…

Go语言物联网开发安科瑞ADW300/4G电能表数据上传mqtt平台-电表接线到传输数据完整流程

电能表功能说明 ADW300是方便用户进行用电监测、集抄和管理&#xff0c;可灵活安装在配电箱中&#xff0c;可用于电力运维、环保监管等在线监测类平台中。我们本案例是用于工业售电公司对出售电的管理&#xff0c;设备可以监控用电情况、故障监控及警报&#xff0c;售电公司可…

解决 ucore lab3 无法触发 page fault 的问题

问题描述 完成清华大学操作系统实验课 ucore(x86) lab3 时&#xff0c;发现无法触发 page fault 异常&#xff0c;具体来说时 check_pgfault() 函数会在执行如下代码时报错 static void check_pgfault(void) {// ......uintptr_t addr 0x100;assert(find_vma(mm, addr) vma…