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


✨✨ 欢迎大家来访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.mfbz.cn/a/597803.html

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

相关文章

【运维自动化-配置平台】如何对主机进行纳管

主机是配置平台管控最常见的资源&#xff0c;也是运维日常主要的管控对象&#xff1b;如何对主机进行全生命周期管理呢导入主机 直接导入 直接导入仅适用于直连区域&#xff08;default area&#xff09;的主机&#xff0c;也就是网络跟蓝鲸平台能内网互通的。 资源–>主…

西奥机电食品质构分析仪:揭秘水果蔬菜硬度等指标的测试原理

西奥机电食品质构分析仪&#xff1a;揭秘水果蔬菜硬度等指标的测试原理 在食品科学领域&#xff0c;对水果蔬菜硬度的精准测量是评估其品质与口感的重要步骤。西奥机电食品质构分析仪凭借其先进的技术和独特的测试原理&#xff0c;为这一领域带来了革命性的变革。下面&#xf…

非标类型导致Dubbo接口出入参异常的本质 | 得物技术

一、概述 笔者支持过程中多次发现诡异的Dubbo接口异常问题&#xff0c;抓耳挠腮最后定位到代码上和代码外的原因&#xff0c;事后只感觉脑瓜子嗡嗡的。考虑到这不是第一次&#xff0c;也绝不会是最后一次出现类似问题&#xff0c;下面笔者将尽可能详细的梳理、总结一下该问题的…

6个月小猫成长必备!福派斯无麸质幼猫粮评测

你知道吗&#xff1f;给小猫选择适合的猫粮是一件非常不容易但很重要的事情。那么&#xff0c;对于6个月大的小猫来说&#xff0c;什么样的猫粮是最适合它们的呢&#xff1f;&#x1f431; 我们首先要考虑的是猫粮的营养成分。6个月大的小猫正处于快速生长期&#xff0c;所以需…

vue3 + ts实现canvas绘制的waterfall

实际运行效果(仅包含waterfall图表部分) component.vue <template><div ref="heatmap" :style="{ height: props.containerHeight + px }" /> </template><script setup> import ColorMap from "colormap"; import…

Labels and Databases for Mac:强大的标签与数据库管理工具

Labels and Databases for Mac是一款集标签制作与数据库管理于一体的强大工具&#xff0c;专为Mac用户打造&#xff0c;旨在提供高效、便捷的标签制作与数据管理体验。 这款软件拥有丰富的内置标签格式&#xff0c;用户可轻松创建各种标签、信封和卡片&#xff0c;满足个性化需…

掌控网络流量,优化网络性能 - AnaTraf网络流量分析仪登场

在当今日新月异的网络环境中,网络流量监控和性能诊断已成为企业IT部门不可或缺的重要工作。只有充分了解网络流量状况,才能有效优化网络性能,提高业务运营效率。针对这一需求,全新推出的AnaTraf网络流量分析仪应运而生,为企业提供全面的网络监控和性能诊断解决方案。 快速定位…

Java双亲委派机制

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 概述 Java程序在运…

pygame实现鼠标绘制并调节画笔大小

pygame实现鼠标绘制并调节画笔大小 pygame介绍调节画笔大小鼠标绘制效果 pygame介绍 Pygame是一个开源的Python库&#xff0c;专为电子游戏开发而设计。它建立在SDL&#xff08;Simple DirectMedia Layer&#xff09;的基础上&#xff0c;允许开发者使用Python这种高级语言来实…

C语言趣味代码(五)

我想以此篇结束关于C语言的博客&#xff0c;因为在C语言拖得越久越不能给大家带来新的创作&#xff0c;在此我也相信大家对C语言已经有了一个新的认知。进入正题&#xff0c;在这一篇中我主要编一个“英语单词练习小程序”来给大家展开介绍&#xff0c;从测试版逐步改良&#x…

数据结构——图的基础知识与其表示

一&#xff1a;定义 由顶点的集合和边的集合组成&#xff1b;常以 G(V,E) 表示&#xff0c;G 代表图&#xff0c;V代表 顶点的集合&#xff0c;E代表边的集合&#xff1b; 如图&#xff1a; 在G1图中&#xff0c;有 0~4 五个顶点&#xff0c;有 0-1&#xff0c;0-2&…

专题五_位运算(2)

目录 面试题 01.01. 判定字符是否唯一 解析 题解 268. 丢失的数字 解析 题解 371. 两整数之和 解析 题解 面试题 01.01. 判定字符是否唯一 面试题 01.01. 判定字符是否唯一 - 力扣&#xff08;LeetCode&#xff09; 解析 题解 class Solution { public:bool isUnique…

Ubuntu上使用audit2allow解决Android Selinux问题

1.安装工具 sudo apt install policycoreutils 2.运行命令 提前用dmesg或者串口抓取kernel log 遇到错误&#xff0c;提示需要用-p指定policy file&#xff0c;然偶尝试创建一个policy空文件&#xff0c;用-p选项&#xff0c;遇到如下错误 3.规避问题 首先跟进错误log的堆栈…

面试集中营—Spring篇

Spring 框架的好处 1、轻量&#xff1a;spring是轻量的&#xff0c;基本的版本大约2MB&#xff1b; 2、IOC&#xff1a;控制反转&#xff0c;Spring的IOC机制使得对象之间的依赖不再需要我们自己来控制了&#xff0c;而是由容易来控制&#xff0c;一个字&#xff1a;爽&#xf…

leetcode-有重复数字的全排列-98

题目要求 思路 1.同【没有重复项的全排列-97】这个题一样&#xff0c;都是递归的题&#xff0c;区别在于这个可能会包含重复的数字&#xff0c;因此&#xff0c;不能只是简单的通过两个值是否相等然后用标志位标记&#xff0c;而是新增了一个数组&#xff0c;这个数组专门用于…

libevent的使用

文章目录 libevent封装的框架思想常用函数分析使用fifo的读写未决和非未决bufferevent特性bufferevent函数客户端和服务器连接和监听libevent实现socket通信 libevent封装的框架思想 libevent框架&#xff1a;1. 创建 event_base (乐高底座)2. 创建 事件evnet 3. 将事件 添加…

【C++练级之路】【Lv.20】位图和布隆过滤器(揭开大数据背后的神秘面纱)

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、位图1.1 位图的概念1.2 位图的优势1.3 位图的模拟实现1.3.1 成员变量与默认成员函数1.3.2 test1.3.3…

AI智能分析视频监控行业的发展趋势和市场发展浅析

监控视频AI智能分析技术的现状呈现出蓬勃发展的态势&#xff0c;这一技术源于计算机视觉和人工智能的研究&#xff0c;旨在将图像与事件描述之间建立映射关系&#xff0c;使计算机能够从视频图像中分辨出目标信息。 在技术上&#xff0c;监控视频AI智能分析技术已经实现了对视…

Jenkins 2.164.3 安装插件(当前官网正式版本: 2.440.3 LTS)

Jenkins 2.164.3安装插件 1. 安装jenkins1.1 宿主机安装1.2 docker安装(linux) 2. 登录jenkins3. 修改配置文件 这篇文章如果放在5、6年前写出来毫无意义&#xff0c;因为安装2.164.3之后&#xff0c;推荐的插件即可自动安装。但是在2024年&#xff0c;当前正式版本是2.440.3 L…

【论文阅读】 Loss Functions for Image Restoration with Neural Networks

Loss Functions for Image Restoration with Neural Networks 论文地址摘要I. 引言II 相关工作用于图像恢复的神经网络B 找到更好的解决方案。 三、图像恢复的损失层A. l1 错误 The l1 ErrorB. SSIMC. MS-SSIMD. The Best of Both Worlds: MS-SSIM L1 四、结果A. Joint Denois…