引用,内联函数,auto函数,指针nullptr

一:引用

1.1

该文章的引用是对上一篇引用的进行补充和完善

按理来说,double可以隐式转换为int,那起别名的时候为什么不可以类型转换呢?

那是因为,在类型转换的时候,会创建一个临时变量,让后再把临时变量赋值给我们创建的变量

而不能直接用int&就是在临时变量这里出了问题,临时变量默认是具有常性的(即不可改变),所以如果直接将常性的值赋给int&相当于权限的放大

正确的写法应该是用cosnt修饰别名

int main()
{double d = 3.14;int i = d;//隐式转换const int& a = d;return 0;
}

相同原理的还有表达是计算,计算结果是放在一个临时变量,在赋值给我们创建的变量的

也应该用const修饰别名

结论:类型转换和表达式计算会产生临时变量,而临时变量具有常性,如果创建别名时,要用const修饰

1.2传值和传别名效率比较

以值作为参数或者返回值类型,在传参和返回值期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时拷贝,因此用值作为参数或者返回类型,效果是十分低下的,尤其是当参数或者返回值类型非常大时,效率就更低了。

1.3指针和引用的区别

1.引用在概念上定义一个变量的别名,指针存储一个变量的地址。(在语法层面上,引用不开额外的空间,而指针开

        其实底层逻辑上,两者均要开空间(平时说两者区别时,都是说语法层面上的)

2. 引用在定义时必须初始化,指针没有要求,但是为了避免野指针问题,最好也初始化

3.引用在初始化一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型的实体

4.没有NULL引用,但有NULL指针(是相对的,不是绝对的,如果硬要写,也可以写)

这样对ptr所指向的空间起一个别名,并不会报错误,但是有人会疑问,不是对ptr解引用了吗?为什么不会不会报错呢?

这是就要讨论起别名的底层逻辑了,在底层是建立一个空间,并没有对ptr解引用,所以不会报错了,但是如果要打印,就会访问NULL了,就会报错

5.在sizeof的含义不同:引用结果为引用类型的大小,但是指针始终是地址空间所占字节的大小(32为机器下占4个字节)

6.引用自加时实体的值加一,指针自加即指针向后偏移一个类型的大小

7.有多级指针,没有多级引用

8.访问实体方式不同,指针需要显示解引用,引用编译器自己处理

9.引用比指针使用起来更安全

10但这并不意味着,引用会把指针完全替代

在链表中,如果要改变链表的指向,就必须要用指针,引用无法改变指向


二.内联函数

2.1概念

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

有call就会根据函数地址,调转到函数所在的栈帧。

但是,如果在上述函数前增加inline关键字将其改为内联函数,在编译期间编译器会用函数体替换函数的调用。

inline int Add(int x, int y)
{return x + y;}int main()
{int ret = 0;ret = Add(1, 2);return 0;
}

2.2特性 

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

缺陷:可能使目标文件变大,优势:少了调用开销,提高程序运行效率

 2.inline对于编译器而言只是一个建议,不同编译关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现),不是递归,且调用频繁的函数采用inline修饰,否则编译器会忽略inline的特性。在《C++prime》第五版中关于inline的建议:内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求

一般来说,内联机制用于优化规模小,流程直接,频繁调用的函数。很多编译器都不支持内联递归函数,而且一个75行的函数也不大可能在调用点内联地展开。

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

 所以,建议,如果要使用内联函数,不要将声明和定义分开,直接在头文件中就定义函数

2.3 

宏的优点:

1.增强代码的复用性

2.提高性能

缺点:

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

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

3.没有类型安全的检查

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

1.常量定义 换用const enum

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


三:auto函数

3.1类型别名的思考

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

1.类型难拼

2.含义不明确导致容易出错

很多人会想到可以用typedef起别名,但是有时会遇到其他问题:

这是为什么呢?

第一条语句,替换以后是char* cosnt p; const修饰的是p指向的内容, 指向的内容只可读不可修改,所以应该初始化

3.2auto的简介

在早期C++/C语言中auto的含义是:使用auto修饰变量,是具有自动存储器的局部变量,但是遗憾的是一直没有人使用它。

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

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

3.3auto的使用细则

3.3.1 auto与指针和引用结合起来用

用auto声明指针类型时,用 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;cout << x << endl;*b = 30;cout << x << endl;c = 40;cout << x << endl;return 0;
}

3. 3.2在一行定义多个变量

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

3.4auto不能推导的场景

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

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

 2.a==++uto不能直接用来声明数组(规定)

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

3.为了避免与C++98中的auto发生混淆,C++11只保留auto作为类型指示符的用法

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


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

4.1范围for的语法

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

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

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

取a中的值赋给e,相当于创建了一个临时变量,将a的值给e,所以改变e时,数组中的值不变

所以这是,可以用别名

void TestFor()
{int a[] = { 1,2,3,4,5 };//自动取a数组中的值赋值给e//自动++,自动结束for (auto& e : a) //用int&(数组对应的类型) 也可以,但是为了方便一般直接用auto&e *= 2;for (auto e : a)cout << e << " ";}
int main()
{TestFor();return 0;
}

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

4.2范围for的使用条件

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

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

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

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

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


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

5.1C++98中的指针空值

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

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

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

#define 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表示指针空值时,不需要包含头文件,因为nulltpr是C++11作为新的关键字引入的

2.在C++11中,sizeof(nullptr)与sizeof((void*)0)所占的字节是相同的

3.为了提高代码的健壮性,在后续表达指针空值时,建议最好使用nullptr

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

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

相关文章

如何提高小红书笔记的收录率?

在小红书平台上&#xff0c;笔记的收录率是衡量一篇笔记是否受欢迎和有价值的重要因素。为了提高笔记的收录率&#xff0c;有几个关键点需要注意&#xff1a; 1.内容不涉及广告 在发布笔记前要先确保笔记内容不包含任何形式的广告或推广信息。小红书平台对于广告性质的内容有…

24年大一训练一(东北林业大学)

前言&#xff1a; 周五晚上的训练赛&#xff0c;以后应该每两周都会有一次。 正文&#xff1a; Problem:A矩阵翻转&#xff1a; #include<bits/stdc.h> using namespace std; int a[55][55]; int main(){int n,m;while(cin>>n>>m){for(int i1;i<n;i){for…

Mysql数据库:故障分析与配置优化

目录 前言 一、Mysql逻辑架构图 二、Mysql单实例常见故障 1、无法通过套接字连接到本地MySQL服务器 2、用户rootlocalhost访问被拒绝 3、远程连接数据库时连接很慢 4、无法打开以MYI结尾的索引文件 5、超出最大连接错误数量限制 6、连接过多 7、配置文件/etc/my.cnf权…

PDF转成二维码分享

在制作电子产品册之前&#xff0c;你需要思考以下几个问题&#xff1a;你的电子产品册是面向什么人群的&#xff1f;是宣传册、使用手册还是产品介绍册&#xff1f;明确目标与定位有助于我们更好地规划产品册的内容和风格。 一、收集素材与整理信息 在开始制作之前&#xff0c…

latex学习笔记

一 安装latex&#xff08;vscodetexlive&#xff09; 安装latex学习链接&#xff1a; 【超详细】最好用LaTex环境安装配置手把手教学&#xff01;&#xff01;&#xff08;支持双向搜索&#xff0c;附赠所需安装包及竞赛模板&#xff09;_哔哩哔哩_bilibilihttps://www.bilib…

KeepAlived使用介绍

目录 1、Introduce 2、基本使用 &#xff08;1&#xff09;安装 &#xff08;2&#xff09;配置文件 &#xff08;3&#xff09;使用教程 1、Introduce keepalived是一个用于实现高可用性和负载均衡的开源软件。它提供了一种轻量级的方式来管理多个服务器&#xff0c;并确保…

高效解决Ubuntu Server 18.04.1 LTS 64bit更新gdb8.1.1到gdb12.1

文章目录 问题解决步骤 问题 因为需要用到gdb一些指令&#xff0c;但是gdb8.x好像存在普遍的问题&#xff0c;实现不了某些指令&#xff0c;比方说set detach-on-fork on&#xff0c;升级版本也没有比较好的教程 经过我不断的试错&#xff0c;我终于升级成功了&#xff01;&a…

【学习笔记】java项目—苍穹外卖day02

文章目录 苍穹外卖-day02课程内容1. 新增员工1.1 需求分析和设计1.1.1 产品原型1.1.2 接口设计1.1.3 表设计 1.2 代码开发1.2.1 设计DTO类1.2.2 Controller层1.2.3 Service层接口1.2.4 Service层实现类1.2.5 Mapper层 1.3 功能测试1.3.1 接口文档测试1.3.2 前后端联调测试 1.4 …

[C++11]可变参数模板

导览&#xff1a; 本章将从可变参数模板的概念开始讲起&#xff0c;到其究竟是如何做到实例化的再从实例出发&#xff0c;探究该如何编写可变参数模板最后涉及可变参数模板的运用 什么是可变参数模板 让我们先见一下可变参数模板 template<typename ...Args> void te…

【SpringCloud】一文详谈Nacos

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》《项目实战》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 …

Linux之用户账号、用户组和与账号有关的系统文件

目录 一、基本介绍 1.用户和用户组 2.UID和GID 二、 账户管理 1.查看用户的UID和GID 2.添加账户 3.删除账号 4.修改账号 5.账户口令 三、分组管理 1.新增用户组 2.删除用户组 3.修改用户组 4.用户组切换 四、与账号有关的系统文件 1./etc/passwd 2./etc/shado…

李宏毅深度强化学习导论——当奖励是稀疏的

引言 这是李宏毅强化学习的笔记&#xff0c;主要介绍如何处理稀疏奖励问题。 稀疏奖励 当我们拿Actor和环境互动后可以得到很多奖励&#xff0c;整理之后可以得到分数 A A A&#xff0c;然后可以训练Actor。 但RL中有时会出现多数情况下奖励为零&#xff0c;此时我们不知道动…

行存储与列存储:大数据存储方案的选择与优缺点分析

随着大数据时代的来临&#xff0c;数据的规模和复杂性呈指数级增长&#xff0c;传统的关系数据库已经不再适应这一巨大的存储量和计算要求。在大数据存储领域&#xff0c;行存储和列存储成为两种备受关注的存储方案。本文将探讨行存储和列存储的定义、优缺点&#xff0c;并结合…

第十四届省赛大学B组(C/C++)岛屿个数

目录 题目链接&#xff1a;岛屿个数 解题思路&#xff1a; AC代码&#xff08;BFSDFS&#xff09;&#xff1a; 题目链接&#xff1a;岛屿个数 小蓝得到了一副大小为 MN 的格子地图&#xff0c;可以将其视作一个只包含字符 0&#xff08;代表海水&#xff09;和 1&#xff0…

LeetCode-331. 验证二叉树的前序序列化【栈 树 字符串 二叉树】

LeetCode-331. 验证二叉树的前序序列化【栈 树 字符串 二叉树】 题目描述&#xff1a;解题思路一&#xff1a;看提示主要是栈和树。这题其实不是二叉树的遍历题&#xff0c;而是检验二叉树基础知识的题&#xff0c;也许有些难想。第一种解法是&#xff1a;把有效的叶子节点使用…

【DETR系列目标检测算法代码精讲】01 DETR算法03 Dataloader代码精讲

与一般的Dataloader的区别在于我们对图像进行了随机裁剪&#xff0c;需要进行额外的操作才能将其打包到dataloader里面 这一段的代码如下&#xff1a; if args.distributed:sampler_train DistributedSampler(dataset_train)sampler_val DistributedSampler(dataset_val, shu…

Python 自学(九) 之异常处理,文件及目录操作

目录 1. try ... except ... else ... finally 排列 P231 2. write, read, seek, readline, readlines 基本文件操作 P245 3. os模块 基本目录操作 P249 4. os.path 模块 复杂目录操作 P250 5. os 模块 高…

Spring之循环依赖

什么是循环依赖? 依赖的相互引用,如下列的这种形式 Component public class A {Autowiredprivate B b;}Component public class B {Autowiredprivate A a; } Spring是如何解决循环依赖的 Spring是通过三级缓存来解决循环依赖 singletonObjects : 单例bean,已经实例化,完成…

牛客2024年愚人节比赛(A-K)

比赛链接 毕竟是娱乐场&#xff0c;放平心态打吧。。。 只有A一个考了数学期望&#xff0c;其他的基本都是acmer特有的脑筋急转弯&#xff0c;看个乐呵即可。 A 我是欧皇&#xff0c;赚到盆满钵满&#xff01; 思路&#xff1a; 我们有 p 1 p_1 p1​ 的概率直接拿到一件实…

Redis改造原始代码

基础篇Redis 5.2.2.改造原始代码 代码说明: 1.在我们完成了使用工厂设计模式来完成代码的编写之后&#xff0c;我们在获得连接时&#xff0c;就可以通过工厂来获得。 &#xff0c;而不用直接去new对象&#xff0c;降低耦合&#xff0c;并且使用的还是连接池对象。 2.当我们…