中秋国庆内卷之我爱学习C++

在这里插入图片描述

文章目录

  • 前言
  • Ⅰ. 内联函数
    • 0x00 内联函数和宏的比较
    • 0x01 内联函数的概念
    • 0x02 内联函数的特性
  • Ⅱ. auto(C++ 11)
    • 0x00 auto的概念
    • 0x01 auto的用途
  • Ⅲ. 范围for循环(C++11)
    • 0x00 基本用法
    • 0x01 范围for循环(C++11)的使用条件
  • Ⅳ. 指针空值nullptr(C++11)
    • 0x00 概念


前言

亲爱的夏目友人帐的小伙伴们,今天我们继续讲解 C++ 入门的知识 内联函数auto范围for循环nullptr空指针 这里的知识虽然入门,但是却是你后面更加深入学习 C++ 知识的钥匙,所以请跟着夏目学长一起进入 C++ 的世界吧!


Ⅰ. 内联函数

0x00 内联函数和宏的比较

我们学习C语言的时候知道:调用函数需要建立栈帧,栈帧中要保存寄存器,结束后就要恢复,这其中都是有 消耗 的 例如:

#include<iostream>using namespace std;int add(int a,int b)
{return a + b;
}int main()
{add(1, 2);add(1, 2);add(1, 2);add(1, 2);return 0;
}

而针对 频繁调用 的 代码短小的函数,可以用 优化,因为宏是在预处理阶段完成替换的,并没有执行时的开销,并且因为代码量小,也不会造成代码堆积,例如:

#include<iostream>using namespace std;#define add(a,b) ((a)+(b)) int main()
{cout << add(1, 2) << endl;return 0;
}

我们会思考,既然宏这么好用,好处如此之多,为什么还要引进 内联函数? 所以下面就要来讲讲 宏 的缺点:

  1. 不能调试
  2. 有些场景下非常复杂
  3. 没有类型安全的检查

就拿我们写过的add函数来说,我们再初次学习的时候通常会写成以下错误:

// 以下代码都是错误的,不要被误导
#define add(int a,int b) ((a)+(b)) 
#define add(int a,int b) ((a)+(b));
#define add(a,b) ((a)+(b));
#define add(a,b) a+b

所以写宏时出错,要么是替换出错,要么是因为优先级出错,所以宏并不友好。

而 C++ 针对为了减少函数调用开销,又可以在一定程度上替代宏,避免宏的出错,从而设计出了内联函数

内联函数的关键字为 inline

#include<iostream>using namespace std;inline int add(int a,int b)
{int res = a + b;return res;
}int main()
{int res = add(1, 2);cout << res << endl;return 0;
}

0x01 内联函数的概念

在 release 版本下,inline 内联函数会直接在调用部分展开;对于 debug 则需要 主动设置 (debug 下编译器默认不对代码做优化);但是 release 版本下其他版本优化的太多,可能就不太好观察,所以我们设置一下编译器,在 debug 下看:

打开解决方案资源管理器,右击项目名称,选中属性并打开,在 C/C++ 区域常规部分,在调试信息一栏设置格式为程序数据库:

在这里插入图片描述

然后找到优化,将内联函数扩展部分选中只适用于 _inline :

在这里插入图片描述
这样算是可以使用内联函数了,就不再需要使用 宏 啦。

0x02 内联函数的特性

  1. inline是一种以 空间换时间 的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
  2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:**将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。**下图为《C++prime》第五版关于inline的建议:在这里插入图片描述
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

对于特性1的讲解:

空间换时间是因为反复调用内联函数,导致编译出来的可执行程序变大

inline void func()
{// 假设编译完成为 10 条指令
}

若不用内联函数,不展开,若10000次调用 func,每次调用的地方为 call 指令的形式,总计 10010 行指令。若用内联函数,则展开,若一千次调用,每次调用的地方为都会展开为 10 条指令,总计 10 * 10000 行指令。

展开会让编译后的程序变大,如果递归函数作内联,后果可想而知。所以长函数和递归函数不适合展开。

对于特性2的讲解:

编译器可以忽略内联请求,内联函数被忽略的界限没有被规定,一般10行以上就被认为是长函数,当然不同的编译器不同

编辑器并不信任你是否能判断什么时候使用内联函数,所以编译器会决策是否使用内联函数。

对于特性3的讲解:

内联函数声明和定义不可分离

由于内联函数无地址,所以当声明和定义分离,调用函数时,由于内联函数无地址,编译器链接不到,所以就会报错,为链接错误。

结论:简短,频繁调用的小函数建议定义成 inline .

Ⅱ. auto(C++ 11)

0x00 auto的概念

在前面学习的C语言当中也有关键字 auto

int main()
{auto int a = 0;
}

auto 关键字修饰后,a变为自动存储类型,即变量会在函数结束以后自动销毁。但是这个语法完全多此一举,因为后来,对于局部变量默认就是自动存储类型,当函数结束后也会自动销毁。

于是 C++ 委员会废弃了 auto 的用法,赋予了新的意义:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

int main()
{int a = 0;int b = 0;auto c = a;auto d = 1.11;auto e = 'a';return 0;
}

对于 auto ,如果要加上 const 属性,则需要主动加上:

int main()
{int x = 10;const auto y = x;cout << typeid(y).name() << endl; // 这里不会打印出,需要调试看return 0;
}

0x01 auto的用途

auto 具有两种针对场景:

  1. 类型难于拼写
  2. 含义不明确导致容易出错

比如后面的STL迭代器的使用 还有 BFS对于取出 pair 类型的时候,这里需要后面学到的时候再讲。

Ⅲ. 范围for循环(C++11)

0x00 基本用法

之前对于数组的遍历,需要使用下标遍历:

int main()
{**加粗样式** int a[] = {1,2,3,4,5,6};for(int i = 0 ; i < sizeof(a) / sizeof(a[0]) ; ++ i){cout << a[i] << ' ';}cout << endl;return 0;
}

而 C++ 中效仿新语言,加入了范围遍历:

int main()
{int a[] = {1,2,3,4,5,6};for(auto& c : a){cout << c << " "; }cout << endl;return 0;
}

范围 for 对于遍历来说非常舒服

而范围for循环的原理就是自动取遍历目标的每一个元素,再放到给定的临时变量中。在上方就是取 arr 的元素放到 num 中,并自动判断结束。auto 会根据遍历目标的元素类型自动推导,当然直接写类型 int 也对 。

而对于 num 的生命周期,则可以认为仅在每次范围遍历中(某一次循环)才存在。

范围 for 会根据遍历目标的元素类型来取出元素,例如上方例子就是 int ,如果这时用指针接收,就是错误的:

int main()
{int a[] = {1,2,3,4,5,6};for(auto* c : a)//错误{c ++;}for(auto c : a){cout << c << " "; }return 0;
}

因为取出来的每一个元素是 int ,类型不匹配。而判断结束我们并不用担心,其实和普通遍历类似。

0x01 范围for循环(C++11)的使用条件

for循环迭代的范围必须是确定的

对于数组的范围就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供beginend的方法,beginend就是for循环迭代的范围。

以下代码就有问题,因为for的范围不确定,因为函数传参,数组就会退化为指针:

void Func_For(int arr[])
{for (auto& c : arr){cout << c << endl;}
}

是错误的。

Ⅳ. 指针空值nullptr(C++11)

0x00 概念

对于 c 来说,空指针为 NULL,是一个宏。

在 C++98/03 时,只能使用 NULL ;而 C++11 后,推荐使用 nullptr 。

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

实际上 NULL 就是个宏,所以说写成 int* p = 0 ,也可以;而j绝大多数情况下,这样写都没问题。

但是对于极端场景:

void f(int) // 这边由于不使用形参,不给形参名也可以
{cout << "f(int)" << endl;
}void f(int*)
{cout << "f(int*)" << endl;
}int main()
{f(0);f(NULL);return 0;
}

按道理,对于第一次调用,应该匹配第一个,对于第二次调用,应该匹配第二个。

但是实际上它们都匹配了第一个,原因是 NULL 是一个宏,本质为 0 .

在C++98中,字面常量 0 既可以是一个整形数字,也可以是无类型的指针(void* )常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void* )0,例如:(int*)NULL ,所以在 C++11 后,使用 nullptr 是明智的选择。

  1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
  2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

在这里插入图片描述

📌 [ 笔者 ]   夏目浅石.
📃 [ 更新 ]   2023.9[ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,本人也很想知道这些错误,恳望读者批评指正!

📜 参考文献:

百度百科[EB/OL]. []. https://baike.baidu.com/.
维基百科[EB/OL]. []. https://zh.wikipedia.org/wiki/Wikipedia
B. 比特科技. C/C++[EB/OL]. 2021[2021.8.31]

在这里插入图片描述如果侵权,请联系作者夏目浅石,立刻删除

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

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

相关文章

Flutter实现PS钢笔工具,实现高精度抠图的效果。

演示&#xff1a; 代码&#xff1a; import dart:ui;import package:flutter/material.dart hide Image; import package:flutter/services.dart; import package:flutter_screenutil/flutter_screenutil.dart; import package:kq_flutter_widgets/widgets/animate/stack.dart…

【Vue】快速入门和生命周期

目录 前言 一、vue的介绍 1. Vue.js是什么&#xff1f; 2. 库和框架的区别 3.基本概念和用法&#xff1a; 二、MVVM的介绍 1. 什么是MVVM&#xff1f; 2. MVVM的组成部分 3. MVVM的工作流程 4. MVVM的优势 5. MVVM的应用场景 三、vue实例 1.模板语法&#xff1a; …

智慧公厕是提升公共厕所管理服务能力的创新举措

在城市化进程加速的今天&#xff0c;公共厕所的管理问题成为让人头疼的难题。随着智慧科技的发展&#xff0c;智慧公厕应运而生&#xff0c;为提升公共厕所综合管理服务能力提供了新思路和解决方案。本文将以智慧公厕领先厂家广州中期科技有限公司&#xff0c;大量精品案例项目…

卡尔曼滤波(Kalman Filter)原理浅析-数学理论推导-4

目录 前言数学理论推导1. 直观理解与二维实例2. EKF3. 补充知识-线性化结语参考 前言 最近项目需求涉及到目标跟踪部分&#xff0c;准备从 DeepSORT 多目标跟踪算法入手。DeepSORT 中涉及的内容有点多&#xff0c;以前也就对其进行了简单的了解&#xff0c;但是真正去做发现总是…

搞定ESD(一):静电放电测试标准解析

文章目录 一、基本术语与定义1.1 基本定义1.2 重要基本术语 二、静电放电发生器介绍2.1 静电放电发生器的特性&#xff1a;通用规范【GB/T17626.2-2018 标准】2.2 ESD 放电发生器电极规格要求&#xff1a;通用规范【GB/T17626.2-2018 标准】2.3 放电回路电缆的要求&#xff1a;…

黑马JVM总结(十四)

&#xff08;1&#xff09;分代回收_1 Java虚拟机都是结合前面几种算法&#xff0c;让他们协同工作&#xff0c;具体实现是虚拟机里面一个叫做分代的垃圾回收机制&#xff0c;把我们堆内存大的区域划分为两块新生代、老年代 新生代有划分为伊甸园、幸存区Form、幸存区To 为什…

进程同步与互斥

目录 进程同步与互斥&#xff08;1&#xff09; 第一节、进程间相互作用 一、相关进程和无关进程 二、与时间有关的错误 第二节、进程同步与互斥 一、进程的同步 二、进程的互斥 三、临界区 进程同步与互斥&#xff08;2&#xff09; 三、信号量与P、V操作的物理含义…

防泄密软件推荐(数据防泄漏软件好用榜前五名)

在当今的数字化时代&#xff0c;数据已经成为企业最宝贵的资产之一。企业需要依赖数据来驱动业务决策、提高运营效率和创新产品。然而&#xff0c;随着数据量的不断增长&#xff0c;数据安全问题也日益凸显。企业需要采取有效的措施来保护敏感数据&#xff0c;防止信息泄露给竞…

算法通关村第16关【青铜】| 滑动窗口思想

1. 滑动窗口的基本思想 一句话概括就是两个快慢指针维护的一个会移动的区间 固定大小窗口&#xff1a;求哪个窗口元素最大、最小、平均值、和最大、和最小 可变大小窗口&#xff1a;求一个序列里最大、最小窗口是什么 2. 两个入门题 &#xff08;1&#xff09;子数组最大平…

使用FastChat部署Baichuan2

1. 引言 近来&#xff0c;大型语言模型的市场需求呈现出蓬勃发展的态势。然而&#xff0c;仅仅掌握模型的数据准备和训练是不够的&#xff0c;模型的部署方法也变得至关重要。在这篇文章中&#xff0c;我们将以Baichuan2为例&#xff0c;利用FastChat进行模型部署的实战操作。…

使用亚马逊云服务器在 G4 实例上运行 Android 应用程序

随着 Android 应用程序和游戏变得越来越丰富&#xff0c;其中有些甚至比 PC 上的软件更易于使用和娱乐&#xff0c;因此许多人希望能够在云上运行 Android 游戏或应用程序&#xff0c;而在 EC2 实例上运行 Android 的解决方案可以让开发人员更轻松地测试和运行 Android 应用程序…

MySQL 笔试——多表连接查询

一、&#xff08;左、右和全&#xff09;连接概念 内连接&#xff1a; 假设A和B表进行连接&#xff0c;使用内连接的话&#xff0c;凡是A表和B表能够匹配上的记录查询出来。A和B两张表没有主付之分&#xff0c;两张表是平等的。 关键字&#xff1a;inner join on 语句&#xf…

Spring之依赖注入源码解析

基于Autowired的依赖注入底层原理 基于Resource注解底层工作流程图&#xff1a; 1 Spring中到底有几种依赖注入的方式&#xff1f; 首先分两种&#xff1a; 手动注入 自动注入 1.1 手动注入 在XML中定义Bean时&#xff0c;就是手动注入&#xff0c;因为是程序员手动给某…

MySQL高级语句 Part2(视图表 +存储过程+条件语句+循环语句)

这里写目录标题 一、视图表 create view1.1 视图表概述1.2 视图表能否修改&#xff1f;&#xff08;面试题&#xff09;1.3 基本语法1.3.1 创建1.3.2 查看1.3.3 删除 1.4 通过视图表求无交集值 二、case语句三、空值(null) 和 无值( ) 的区别四、正则表达式4.1 基本语法和匹配模…

css,环形

思路&#xff1a; 1.先利用conic-gradient属性画一个圆&#xff0c;然后再叠加 效果图 <template><div class"ring"><div class"content"><slot></slot></div></div> </template> <script> import …

【力扣每日一题】2023.9.24 LRU缓存

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这又是一道程序设计类的题目&#xff0c;要我们实现LRU缓存的get和put操作。 简单说一下LRU缓存是什么&#xff0c;在我看来就是实用主义…

【李沐深度学习笔记】矩阵计算(2)

课程地址和说明 线性代数实现p4 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 本节是第二篇 矩阵计算 矩阵的导数运算 此处参考了视频&#xff1a;矩阵的导数运算 为了方便看出区别&#xff0c;我将所有的向量…

VSCode 配置 Lua 开发环境(清晰明了)

概述 由于 AutoJS 学得已经差不多了&#xff0c;基本都会了&#xff0c;现在开始向其他游戏脚本框架进发&#xff0c; Lua 语言很强大&#xff0c;就不多说&#xff0c; 按键精灵、触动精灵等等都是用该语言编程脚本的&#xff0c;由于按键精灵、触动精灵 和 AutoJS 类似,不是…

基于Xml方式Bean的配置-初始化方法和销毁方法

SpringBean的配置详解 Bean的初始化和销毁方法配置 Bean在被实例化后&#xff0c;可以执行指定的初始化方法完成一些初始化的操作&#xff0c;Bean在销毁之前也可以执行指定的销毁方法完成一些操作&#xff0c;初始化方法名称和销毁方法名称通过 <bean id"userService…

后置处理 Bean

目录 ​编辑一、后置处理 Bean 1、后置处理 Bean 的运行原理分析 2、BeanPostProcessor 的开发步骤 &#xff08;1&#xff09;实现 BeanPostProcessor 接口 &#xff08;2&#xff09;Spring 的配置文件配置 &#xff08;3&#xff09;细节 一、后置处理 Bean BeanPost…