C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字

news2024/11/25 0:25:27


✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭~✨✨

🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。

我是Srlua小谢,在这里我会分享我的知识和经验。🎥

希望在这里,我们能一起探索IT世界的奥妙,提升我们的技能。🔮

记得先点赞👍后阅读哦~ 👏👏

📘📚 所属专栏:​​​C/C++

欢迎访问我的主页:Srlua小谢 获取更多信息和资源。✨✨🌙🌙

​​​​

​​​​  

目录

C++中的引用

引用概念

引用的特性

常引用

使用场景

作为参数

作为返回值

传值、传引用效率比较

引用和指针的区别

在语法概念上

在底层实现上

引用和指针的汇编代码对比

引用与指针的不同点

C++中的内联函数

内联函数概念

调设置前的情况(可能):

查看方式:

调完设置后:

内联函数的特性

思考

宏的优缺点?

优点:

缺点:

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

C++中的auto关键字(C++11)

类型别名思考

范围for循环

范围for循环语法

范围for的使用条件

指针空值nullptr(C++11)

C++98中的指针空值


  

C++中的引用

引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"。

类型& 引用变量名(对象名) = 引用实体;
void TestRef()
{
    int a = 10;
    int& ra = a;//<====定义引用类型
    printf("%p\n", &a);
    printf("%p\n", &ra);
}
注意: 引用类型 必须和引用 实体 同种类型

引用的特性

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体

常引用

void TestConstRef()
{
    const int a = 10;
    //int& ra = a;   // 该语句编译时会出错,a为常量
    const int& ra = a;
    // int& b = 10; // 该语句编译时会出错,b为常量
    const int& b = 10;
    double d = 12.34;
    //int& rd = d; // 该语句编译时会出错,类型不同
    const int& rd = d;
}

使用场景

作为参数

void Swap(int& left, int& right)
{
   int temp = left;
   left = right;
   right = temp;
}

作为返回值

int& Count()
{
   static int n = 0;
   n++;
   // ...
   return n;
}

传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直
接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效
率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。
#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{
 A a;
 // 以值作为函数参数
 size_t begin1 = clock();
 for (size_t i = 0; i < 10000; ++i)
 TestFunc1(a);
 size_t end1 = clock();
 // 以引用作为函数参数
 size_t begin2 = clock();
 for (size_t i = 0; i < 10000; ++i)
 TestFunc2(a);
 size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
 cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
 cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

time 为 0 是因为小于一毫秒

通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大

引用和指针的区别

语法概念上

引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
int main()
{
    int a = 10;
    int& ra = a;
    
    cout<<"&a = "<<&a<<endl;
    cout<<"&ra = "<<&ra<<endl;

    return 0;
}

底层实现上

实际是有空间的,因为引用是按照指针方式来实现的。
{
    int a = 10;

    int& ra = a;
    ra = 20;

    int* pa = &a;
    *pa = 20;

    return 0;
}

引用和指针的汇编代码对比

底层汇编语言里
引用与指针是一样的

都是指针

  

引用与指针的不同点

  1.  引用概念上定义一个变量的别名,指针存储一个变量地址。
  2. 引用在定义时必须初始化,指针没有要求
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  4. 没有NULL引用,但有NULL指针    
  5. sizeof中含义不同引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  7. 有多级指针,但是没有多级引用
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  9. 引用比指针使用起来相对更安全  

C++中的内联函数

内联函数概念

inline修饰 的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方 展开 ,没有函数调
用建立栈帧的开销,内联函数提升程序运行的效率。
如果在函数前增加inline关键字将其改成内联函数,在编译期间编译器会用 函数体替换函数的
调用。

调设置前的情况(可能):

   

查看方式:

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

  

   

调完设置后:

   

内联函数的特性

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

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

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

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

 下图为 《C++prime》第五版关于inline的建议:   3.inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。  

思考

宏的优缺点?

优点:

1.增强代码的复用性。

2.提高性能。

缺点:

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

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

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

C++有哪些技术替代宏

1. 常量定义 换用const enum
2. 短小函数定义 换用内联函数
随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:
1. 类型难于拼写
2. 含义不明确导致容易出错

C++中的auto关键字(C++11)

类型别名思考

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:

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;
}
在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的
是一直没有人去使用它,为什么?
在早期的C语言中,`auto`是一个存储类别修饰符,用于声明具有自动存储期的局部变量。根据C语言的标准,如果局部变量声明时没有指定存储类别,那么默认就是`auto`。因此,在C语言中,`auto`关键字实际上是非常常用的,只是大多数时候是隐式使用的,而不是显式写出来。
C语言标准(如C89/C90)规定,函数内部的局部变量默认是自动存储期限(auto storage duration),这意味着每次函数被调用时,这些变量都会被创建和初始化,当函数返回时,这些变量就会被销毁。由于`auto`是默认的行为,所以在编写代码时通常不需要显式地使用`auto`关键字。
在C++中,`auto`关键字的传统用法与C语言相同,但在C++11标准中,`auto`被赋予了新的含义,用作类型自动推导。这意味着在声明变量时,编译器会自动根据初始化表达式的类型来确定变量的类型。这个特性使得`auto`在C++11及以后的版本中变得非常流行和常用。
总结来说,`auto`在早期C/C++中并不是没有人使用,而是因为它是默认行为,所以通常不需要显式使用。而在C++11及以后的版本中,`auto`的用途被扩展,成为了一个非常实用的特性。
C++11中,标准委员会赋予了auto全新的含义即: auto不再是一个存储类型指示符,而是作为一
个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得
std::map<std::string, std::string>::iterator 是一个类型,但是该类型太长了,特别容易写错。
   
注意:
使用auto定义变量时必须对其进行初始化 ,在编译阶段编译器需要根据初始化表达式来推导auto
的实际类型
因此auto并非是一种“类型”的声明,而是一 个类型声明时的“占位符”,编译器在编 译期会将auto替换为变量实际的类型

范围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也可换为其他字母,不固定,如:x

范围for的使用条件

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

对于数组而言,就是数组中第一个元素和最后一个元素的范围

对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

2. 迭代的对象要实现++和==的操作

指针空值nullptr(C++11)

C++98中的指针空值

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

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

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif
可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何
种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:
程序本意是想通过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/1647592.html

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

相关文章

Spring JdbcTemplate实现自定义动态sql拼接功能

需求描述&#xff1a; sql 需要能满足支持动态拼接&#xff0c;包含 查询字段、查询表、关联表、查询条件、关联表的查询条件、排序、分组、去重等 实现步骤&#xff1a; 1&#xff0c;创建表及导入测试数据 CREATE TABLE YES_DEV.T11 (ID BINARY_BIGINT NOT NULL,NAME VARCH…

LSTM计算指示图

掌握网络结构组件构成 输入门、遗忘门、输出门候选记忆细胞记忆细胞隐藏状态ref&#xff1a;6.8. 长短期记忆&#xff08;LSTM&#xff09; — 《动手学深度学习》 文档 (gluon.ai)

[疑难杂症2024-004] 通过docker inspect解决celery多进程记录日志莫名报错的记录

本文由Markdown语法编辑器编辑完成&#xff0e; 1. 前言 最近我负责的一个服务&#xff0c;在医院的服务器上线一段时间后&#xff0c;利用docker logs查看容器的运行日志时&#xff0c;发现会有一个"莫名其妙"的报错&#xff0e;报错的大致内容就是&#xff0c;ce…

vulhub之git(CVE-2017-8386)

启动靶场环境 查看文件 修改属性 为了不和docker母机的ssh端口冲突&#xff0c;将容器的ssh端口设置成3322。本目录下我生成了一个id_rsa&#xff0c;这是ssh的私钥&#xff0c;连接的时候请指定之。在连接以前&#xff0c;需要先设置私钥的权限为0600&#xff1a;chmod 0600 i…

工业光源环形系列一平面无影光源特点

产品特点 ◆LED灯珠均匀排布经过漫射板特殊角度反射达到漫射效果&#xff1a; ◆光源均匀性高&#xff0c;漫射效果好。

11个值得关注的文本转语音AI大模型

语言模型&#xff0c;尤其是大型语言模型&#xff08;LLM&#xff09;&#xff0c;本质上已经成为人工智能的代表。然而&#xff0c;他们有一个隐秘的问题。到目前为止&#xff0c;人工智能社区主要在文本数据上训练人工智能&#xff0c;而忽略了音频数据。结果&#xff0c;我们…

docker-compose完成mysql8.0+环境搭建

1、准备my.cnf文件到指定目录&#xff08;和基础的增加了一个default_authentication_pluginmysql_native_password 的身份验证插件配置信息&#xff09; 原因&#xff1a;官方提到&#xff1a; 该方式可以解决&#xff1a;Authentication plugin ‘caching_ sha2_password‘ c…

《视觉十四讲》例程运行记录(2)——运行ch4的例程评估轨迹误差

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、运行ch4的example1. 编译例程2. 运行报错(1) 报错一(2) 报错二 一、运行ch4的example 1. 编译例程 (1) 在slambook2/ch4/example目录下&#xff0c;创建build…

Gradle基础学习(六) 认识任务Task

理解Gradle中的任务 Gradle的构建过程基于任务&#xff08;Task&#xff09;的概念&#xff0c;而每个任务都可以包含一个或多个动作&#xff08;Action&#xff09;。 任务是构建中执行的一些独立的工作单元&#xff0c;例如编译类、创建JAR、生成Javadoc或将存档发布到仓库…

人工智能中的知识表示与推理技术概述

人工智能中的知识表示与推理技术概述 一、引言二、知识表示与推理技术概述1. 描述逻辑2. Horn逻辑3. 产生式系统4. 框架系统5. 语义网络 三、知识表示与推理技术的比较四、知识表示与推理技术的未来发展 一、引言 在人工智能&#xff08;AI&#xff09;的漫长演进中&#xff0…

ICode国际青少年编程竞赛- Python-1级训练场-多变量应用

ICode国际青少年编程竞赛- Python-1级训练场-多变量应用 1、 a 1 b 2 for i in range(4):Spaceship.step(a)Dev.step(b)Dev.step(-b)a a 1b b 12、 a 2 b 5 for i in range(3):Spaceship.turnLeft()Spaceship.step(a)Spaceship.turnRight()Spaceship.step(b)a a …

STM32F103学习笔记 | 报错界面及解决方案 | 1.keil5中文注释的横竖(正与斜)问题

文章目录 一、报错界面二、解决方案参考文献 一、报错界面 二、解决方案 打开设置 在打开的设置选项卡中&#xff0c;图中Font显示的是这个软件当前设置的字体&#xff0c;可以看到字体是仿宋&#xff0c;这就是问题出现的原因&#xff0c;将之改成没有的字体就行了。 可以看…

Dell EMC Storage Unity: Remove/Install Memory Module

SP A 一个内存故障 点击system view -> Enclosures->Top查看 再次查看Alert&#xff0c; 确认内存出现问题 进入Service &#xff0c; 将SP A置为service状态 移出SP A &#xff0c;进行内存更换 更换完内存后&#xff0c;将SP A插入设备&#xff0c;并进行线缆连接 进入…

使用免费的数据恢复软件通过简单的步骤恢复丢失的数据

犯错是人之常情&#xff01;您有时可能会意外地从PC或笔记本电脑中删除重要数据&#xff0c;旧的家庭或大学视频/照片&#xff0c;如果您面临数据丢失&#xff0c;则可以使用数据恢复软件轻松恢复丢失的数据。 奇客数据恢复软件可让您从笔记本电脑&#xff0c;PC和可移动存储设…

VALSE 2024特邀报告内容解析|多模态视觉融合方法:是否存在性能极限?

2024年视觉与学习青年学者研讨会&#xff08;VALSE 2024&#xff09;于5月5日到7日在重庆悦来国际会议中心举行。本公众号将全方位地对会议的热点进行报道&#xff0c;方便广大读者跟踪和了解人工智能的前沿理论和技术。欢迎广大读者对文章进行关注、阅读和转发。文章是对报告人…

五分钟了解等级保护、风险评估和安全测评三者的区别和联系?

等级保护 基本概念&#xff1a;网络安全等级保护是指对国家秘密信息、法人和其他组织和公民的专有信息以及公开信息和存储、传输、处理这些信息的信息系统分等级实行安全保护&#xff0c;对信息系统中使用的安全产品实行按等级管理&#xff0c;对信息系统中发生的信息安全事件…

Linux-03

cat 由第一行开始显示文件内容 tac 从最后一行开始显示&#xff0c;可以看出 tac 是 cat 的倒着写 nl 显示的时候&#xff0c;顺道输出行号 more 一页一页的显示文件内容 less 与 more 类似&#xff0c;但是比 more 更好的是&#xff0c;他可以往前翻页 (空格翻页 退出q命令) h…

不是,有你们这么卖东西的?涨价是肯定的,我苟住不浪也是必然的!——早读(逆天打工人爬取热门微信文章解读)

大家说我苟&#xff0c;我笑他人看不穿 引言Python 代码第一篇 洞见 晕船法则&#xff08;深度好文&#xff09;第二篇 九边 宅男之死结尾 理性的讨论能够促进理解 而不仅仅是赢得争论 我们追求的是通过讨论增进理解 而非仅仅证明自己的正确 引言 最近的言论似乎控制得更加严格…

Study--Oracle-01-单实例部署Oracle11G-R2

Oracle版本发布介绍 Oracle 19c和12c和11g功能区别_数据库_oracle_支持 一、CentOS 7 环境准备 1、软件准备 操作系统&#xff1a;CentOS 7 数据库版本: Oracle11g R2 2、操作系统环境配置 关闭selinux &#xff0c;编辑 /etc/selinux/config文件&#xff0c;设置SELINU…

Elementui的el-footer标签使用报错

Elementui的el-footer标签使用报错 其余标签的使用没有报错信息 el-footer的报错信息 原因: ​ 警告信息表示 Vue 不识别 <el-footer> 解决方式: 在组件中进行引入和暴露