C++入门5.内联函数,auto关键字,基于范围的for循环(C++11),指针空值nullptr(C++11)

本篇是C过度C++初始的最后一篇,快快对入门须知的知识有个印象后,就可以顺顺利利的学习C++的类了。

目录

内联函数:

内联函数的特性:

auto关键字(C++11):

auto简介:

使用细则:

auto不能推导的场景(实际上就一点,不让编译器做选择,歧义的事不要产生) 

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

范围for的语法:

范围for的使用条件

指针空值nullptr(C++11):

C++98中的指针空值


内联函数:

        介绍一种宏的替代品

        1.概念

        inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数能提升程序运行的效率。

,可以自行查看编译器生成的汇编代码查看是否存在call add,以看是否是直接展开代码块

内联函数的特性:

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

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

下图为 《C++prime》第五版关于inline的建议:

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

#define _CRT_SECURE_NO_WARNINGS 1
// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{
	cout << i << endl;
}
// main.cpp
#include "F.h"
int main()
{
	f(10);
	return 0;
}
// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl 
// f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用

【面试题】

 宏的优缺点?

优点:

1.增强代码的复用性。

2.提高性能。

缺点:

1.不方便调试宏。(因为预编译阶段进行了替换)

2.导致代码可读性差,可维护性差,容易误用。

3.没有类型安全的检查 。

C++有哪些技术替代宏?

1. 常量定义 换用const enum

2. 短小函数定义 换用内联函数

博主建议了解规则,看得懂关键词即可(先粗粗过一遍),

auto关键字(C++11):

auto作为一个特殊类型,可以实现自动由编译器在编译时期推导auto所在位置,原本该显示写出来的类型。如果推导不出来,有歧义==GG。

auto简介:

        早期的auto没啥用处,不用记

        C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一 个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

使用细则:

1. auto与指针和引用结合起来使用

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须 加&(很容易想到如果不加&会造成歧义,编译器判断不来)

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
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;
}

2. 在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

auto不能推导的场景(实际上就一点,不让编译器做选择,歧义的事不要产生) 

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

2. auto不能直接用来声明数组(这个特殊一点)

3. 为了避免与C++98(以前的老的用法,已经抛弃了,没必要记)中的auto发生混淆,C++11只保留了auto作为类型指示符的用法

4. auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有 lambda表达式等进行配合使用。

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

范围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 << " ";
}

注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

和正常循环没啥大区别,自动遍历的小技巧,至于怎么取遍历数组(以数组为例)中的每一个值,

在“:”之前。

&取别名,可对数组中的值进行操作,不然便是copy一份而已,至于auto也可自己显示写,这里不过是习惯用法。

范围for的使用条件

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

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

注意:以下代码就有问题,因为for的范围不确定

void TestFor(int array[])
{
	for (auto& e : array)
		cout << e << endl;
}

指针空值nullptr(C++11):

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.mfbz.cn/a/559382.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】帮助类命令

在Linux中&#xff0c;man用于查看系统手册页&#xff08;manual pages&#xff09;。它用于查阅关于特定命令、函数、工具或文件格式的详细信息。要使用man命令&#xff0c;只需在终端中输入man&#xff0c;后跟您要查看的命令或主题的名称。 例如&#xff0c;如果查看ls命令…

【Linux C | 多线程编程】线程同步 | 信号量(无名信号量) 及其使用例子

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

018Node.js安装淘宝镜像(cnpm命令)

http://www.npmjs.org npm包官网 https://npm.taobao.org 淘宝npm镜像官网 淘宝NPM镜像是一个完整npmjs.org镜像&#xff0c;你可以用此替代官方版本&#xff08;只读&#xff09;&#xff0c;同步频率目前为10分钟一次&#xff0c;保证尽量与官方服务同步。 可以定制的cnpm(…

若依前后端部署到一起

引用&#xff1a;https://blog.csdn.net/qq_42341853/article/details/129127553 前端改造&#xff1a; 配置打包前缀 修改router.js 编程hash模式&#xff1a; 前端打包&#xff1a;npm run build:prod 后端修改&#xff1a; 添加thymeleaf包&#xff0c;和配置文件 spri…

Three.js加载glb / gltf模型,Vue加载glb / gltf模型(如何在vue中使用three.js,vue使用threejs加载glb模型)

简介&#xff1a;Three.js 是一个用于在 Web 上创建和显示 3D 图形的 JavaScript 库。它提供了丰富的功能和灵活的 API&#xff0c;使开发者可以轻松地在网页中创建各种 3D 场景、模型和动画效果。可以用来展示产品模型、建立交互式场景、游戏开发、数据可视化、教育和培训等等…

Jenkins用maven风格build报错解决过程记录

1、Jenkins2.453新建项目&#xff0c;构建风格选的maven 2、自由风格构建部署没有任何问题&#xff0c;但是maven风格build一直失败&#xff0c;报错如下图 3、解决方案&#xff1a;在系统管理–系统配置–Maven项目配置&#xff0c;删除全局MAVEN_OPT的路径信息&#xff0c;…

OpenCV基本图像处理操作(四)——傅立叶变换

傅里叶变换的作用 高频&#xff1a;变化剧烈的灰度分量&#xff0c;例如边界 低频&#xff1a;变化缓慢的灰度分量&#xff0c;例如一片大海 滤波 低通滤波器&#xff1a;只保留低频&#xff0c;会使得图像模糊 高通滤波器&#xff1a;只保留高频&#xff0c;会使得图像细节…

事务的传播行为介绍和事务失效

常用的就下图介绍的这两种&#xff0c;REQUIRED 支持当前事务&#xff0c;如果不存在&#xff0c;就新建一个&#xff0c;EQUIRES_NEW 如果有事务存在&#xff0c;挂起当前事务&#xff0c;创建一个新的事务 同一个service中必须用代理对象调用&#xff0c;否则失效

ubuntu22.04下编译ffmpeg和ffplay

Ubuntu22.04 下编译安装 ffmpeg 和 ffplay 一、下载源码包 1.1 官方下载链接&#xff1a;Download FFmpeg 可以手动下载&#xff0c;也可以命令行下载&#xff1a; wget http://www.ffmpeg.org/releases/ffmpeg-7.0.tar.xz 1.2 下载完解压 tar -xvf ffmpeg-7.0.tar.xz…

3.SpringCloud版本

1.SpringCloud与SpringBoot之间版本对应 2.服务拆分的注意事项 1.不同微服务&#xff0c;不要重复开发相同业务。 2.微服务的数据独立&#xff0c;每个微服务都有自己独立的数据库&#xff0c;不要访问其他微服务的数据库。 3.微服务可以将自己的的业务暴露为接口&#xff…

如何选择适用于Mac的iPhone数据恢复软件?

以下是全球无数 Mac 用户每天遇到的场景&#xff1a; 用户丢失了重要文件。用户在搜索中输入术语“iPhone数据恢复软件”。出现了数百个可能合适的软件应用程序&#xff0c;使用户很难决定其中哪一个是最好的。 这并不好&#xff0c;因为iOS数据恢复是一个时间敏感的过程&…

Spring、SpringMVC、SpringBoot核心知识点(持续更新中)

Spring、SpringMVC、SpringBoot核心知识点&#xff08;持续更新中&#xff09; Spring Bean 的生命周期Spring 的 IOC 与 AOPSpring Bean 循环依赖Spring MVC 处理请求的过程Spring Boot 自动装配原理Spring Boot 启动流程 Spring Bean 的生命周期 参考文章&#xff1a;一文读…

提取点云-------PCL

提取点云 /// <summary> /// VoxelGrid滤波下采样 /// </summary> /// <param name"cloud">需要滤波的点云</param> /// <param name"lx">三维体素栅格的x</param> /// <param name"ly">三维体素栅格…

vue 下载文件 处理后台返回的文件流

1. 下载文件很常见&#xff0c;下载成各种格式的也很常见&#xff0c;本质就是后台返回一个文件流&#xff0c;我们前端去处理一下就行&#xff0c;但是如果因为某些条件&#xff0c;没有返回文件流&#xff0c;返回告诉你&#xff0c;文件出现错误了&#xff0c;那我们就需要把…

【机器学习】分类与预测算法的评价与优化

以实际案例解析F1值与P-R曲线的应用 一、分类算法与性能评价的重要性二、F1值与P-R曲线的概念与意义三、实例解析&#xff1a;以垃圾邮件检测为例四、代码实现与结果分析五、结论与展望 在数据驱动的时代&#xff0c;机器学习算法以其强大的数据处理和分析能力&#xff0c;成为…

deepinV23 Beta3 安装Nvidia显卡驱动

文章目录 下载驱动禁用系统自带的nouveau驱动查看系统是否启用了nouveau显卡驱动禁用nouveau 安装重启后报错其他问题安装其他版本的驱动[nvidia-smi 显示 CUDA Version:N/A](https://blog.csdn.net/JiuYux/article/details/137981588) 注意&#xff1a;先看 重启后报错 章节 …

基于TCC的分布式事务

优质博文&#xff1a;IT-BLOG-CN 一、分布式事务简介 分布式的架构中&#xff0c;分布式的事务是一个绕不过的挑战&#xff0c;微服务理念的流行让分布式的问题日益突出。 在公司内部&#xff0c; 笔者所接触的管理系统中实际上也存在着分布式事务。 这里假设有这三个系统&…

Scanpy(2)多种可视化

本篇内容为scanpy的可视化方法&#xff0c;可以分为三部分&#xff1a; embedding的散点图&#xff1b;用已知marker genes的聚类识别&#xff08;Identification of clusters&#xff09;&#xff1b;可视化基因的差异表达&#xff1b; 我们使用10x的PBMC数据集&#xff08;…

全新Linux教程-驱动大全-PCI和PCIe子系统-P5-PCIe设备的配置过程

1 PCIe系统硬件结构 注意&#xff1a;在pci设备中&#xff0c;可以通过引脚选中设备&#xff0c;但是在PCIe设备中&#xff0c;由于是端对端的配置过程&#xff08;endpoint to endpoint&#xff09;。PCIe桥中有很多端口&#xff0c;端口可以直接连接PCIe设备。在设备之间只有…

python连接数据库1

1、建立简单的数据库连接&#xff08;前提是有数据库&#xff09; from pymysql import Connection connConnection(host localhost, #主机名 /ip地址 127.0.0.1port3306, #端口&#xff0c;默认为这个userroot, #账户名password123456 #密码&#xff0c;自己的密码 ) #打印相…
最新文章