我与C++的爱恋:内联函数,auto


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

🔥个人主页guoguoqiang. 🔥专栏我与C++的爱恋

Alt

一、内联函数

1.内联函数的概念

内联函数目的是减少函数调用的开销,通过将每个调用点将函数展开来实现。这种方法仅适用于那些函数体小、调用频繁的函数。

int add(int x,int y){return x+y;
}

假如这里要调用一万次add,那么就要建立一万个栈帧,消耗较大。
在c语言中可以通过 来实现

#define Add(x,y) ((x)+(y))

在C++中把以inline修饰的函数叫做内联函数,(inline在函数声明前)。
inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,直接就执行了函数的代码,减少了函数调用的消耗。
在这里插入图片描述

在这里插入图片描述

#include <iostream>
using namespace std;
inline int Add(int x, int y) {return x + y;
}
int main() {int result = Add(1, 2);cout << result << endl;return 0;
}

Add函数被声明为内联函数,Add(1,2)直接替换为1+2.从而避免了函数调用的开销.

2.内联函数的特性

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

二、auto关键字(C++11)

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

  1. 类型难于拼写
  2. 含义不明确导致容易出错
    在c语言中为了处理这个问题就可以使用typedef来简化代码。
typedef char* pstring;
int main()
{
const pstring p1; // 编译成功还是失败?  编译失败
const pstring* p2; // 编译成功还是失败?
return 0;
}

在编程时,常常需要把表达式的值赋值给变量,这就要求在声明变量的时候清楚地知道表达式的
类型。然而有时候要做到这点并非那么容易,所以就有了auto的由来。
auto声明的变量必须由编译器在编译时期推导而得(它作为一个新的类型指示符来指示编译器)

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

int a=0;
int b=a;
auto a=a
auto b=&a;
auto*c=&a;
auto&c=a;
int TestAuto()
{
return 10;
}
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = TestAuto();
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
return 0;
}

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

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

void TestAuto{auto a=1,b=2;auto c=3,d=4.0;//该行代码会编译失败,因为c和d的初始化类型不同。
}

auto不能推导的场景:
1.auto不能作为函数的参数

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

2.auto不能直接用来声明数组

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

三、范围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循环后的括号由冒号“ :”分为两部分:第一部分是范
围内用于迭代的变量,第二部分则表示被迭代的范围。(在python中也有类似的调用,抄作业了!!)

void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto e : array)
cout << e << " ";
return 0;
}

在这里插入图片描述

如果你想改变原数组里的数据就可以使用引用来改变原数组中的数。

void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)
e *= 2;
for(auto e : array)
cout << e << " ";
return 0;
}

在这里插入图片描述

与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。
循环for的使用条件
for循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供
begin和end的方法,begin和end就是for循环迭代的范围。

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

在这里插入图片描述

四、指针空值

声明一个变量时最好给该变量一个合适的初始值,否则可能会出现
不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们在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。

void f(int) {cout << "f(int)" << endl;
}
void f(int*) {cout << "f(int*)" << endl;
}
int main()
{f(0);f(NULL);f((int*)NULL);f(nullptr);return 0;
}

在这里插入图片描述

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

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

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

相关文章

【JavaWeb】百度地图API SDK导入

百度地图开放平台 | 百度地图API SDK | 地图开发 (baidu.com) 登录注册&#xff0c;创建应用&#xff0c;获取AK 地理编码 | 百度地图API SDK (baidu.com) 需要的接口一&#xff1a;获取店铺/用户 所在地址的经纬度坐标 轻量级路线规划 | 百度地图API SDK (baidu.com) 需要的…

java-ssm-jsp-旅游景点数据库管理系统

java-ssm-jsp-旅游景点数据库管理系统 获取源码——》哔站搜&#xff1a;计算机专业毕设大全 获取源码——》哔站搜&#xff1a;计算机专业毕设大全

自定义树形筛选选择组件

先上效果图 思路&#xff1a;刚开始最上面我用了el-input&#xff0c;选择框里面内容用了el-inputel-tree使用&#xff0c;但后面发现最上面那个可以输入&#xff0c;那岂不是可以不需要下拉就可以使用&#xff0c;岂不是违背了写这个组件的初衷&#xff0c;所以后面改成div自定…

5.vector容器的使用

文章目录 vector容器1.构造函数代码工程运行结果 2.赋值代码工程运行结果 3.容量和大小代码工程运行结果 4.插入和删除代码工程运行结果 5.数据存取工程代码运行结果 6.互换容器代码工程运行结果 7.预留空间代码工程运行结果 vector容器 1.构造函数 /*1.默认构造-无参构造*/ …

StarRocks实战——携程火车票指标平台建设

目录 前言 一、早期OLAP架构与痛点 二、指标平台重构整体设计 2.1 指标查询过程 2.1.1 明细类子查询 2.1.2 汇总类子查询 2.1.3 “缓存” 2.2 数据同步 三、Starrocks使用经验分享 3.1 建表经验 3.2 数据查询 3.3 函数问题 四、查询性能大幅提升 五、 后续优化方…

C++实现二叉搜索树的增删查改(非递归玩法)

文章目录 一、二叉搜索树的概念结构和时间复杂度二、二叉搜索树的插入三、二叉搜索树的查找四、二叉搜索树的删除&#xff08;最麻烦&#xff0c;情况最多&#xff0c;一一分析&#xff09;3.1首先我们按照一般情况下写&#xff0c;不考虑特殊情况下4.1.1左为空的情况&#xff…

多线程--深入探究多线程的重点,难点以及常考点线程安全问题

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

C语言交换二进制位的奇数偶数位

基本思路 我们要先把想要交换的数的二进制位给写出来假如交换13的二进制位&#xff0c;13的二进制位是 0000 0000 0000 0000 0000 0000 0000 1101然后写出偶数位的二进制数&#xff08;偶数位是1的&#xff09; 1010 1010 1010 1010 1010 1010 1010 1010然后写出奇数位的二进…

2012年认证杯SPSSPRO杯数学建模C题(第一阶段)碎片化趋势下的奥运会商业模式全过程文档及程序

2012年认证杯SPSSPRO杯数学建模 C题 碎片化趋势下的奥运会商业模式 原题再现&#xff1a; 从 1984 年的美国洛杉矶奥运会开始&#xff0c;奥运会就不在成为一个“非卖品”&#xff0c;它在向观众诠释更高更快更强的体育精神的同时&#xff0c;也在攫取着巨大的商业价值&#…

Spring Boot Mockito (三)

Spring Boot Mockito (三) 这篇文章主要是讲解Spring boot 与 Mockito 集成测试。 前期项目配置及依赖可以查看 Spring Boot Mockito (二) - DataJpaTest Spring Boot Mockito (一) - WebMvcTest Tag("Integration") SpringBootTest // TestMethodOrder(MethodOr…

go 指针和内存分配

定义 了解指针之前&#xff0c;先讲一下什么是变量。 每当我们编写任何程序时&#xff0c;我们都需要在内存中存储一些数据/信息。数据存储在特定地址的存储器中。内存地址看起来像0xAFFFF&#xff08;这是内存地址的十六进制表示&#xff09;。 现在&#xff0c;要访问数据…

程序员们应注意的行业特有的法律问题

大家好&#xff0c;我是不会魔法的兔子&#xff0c;是一枚执业律师&#xff0c;持续分享技术类行业项目风险及预防的问题。 一直以来兔子都在以大家做项目时候会遇到的风险问题做分享&#xff0c;最近有个念头一直挥之不去&#xff0c;就是要不要给我们广大的程序员们也分享一…

【接口】HTTP(1)|请求|响应

1、概念 Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;用于从万维网&#xff08;就是www&#xff09;服务器传输超文本到本地浏览器的传送协议。 HTTP协议是基于TCP的应用层协议&#xff0c;它不关心数据传输的细节&#xff0c;主要是用来规定客户端和…

【C++练级之路】【Lv.18】哈希表(哈希映射,光速查找的魔法)

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、哈希1.1 哈希概念1.2 哈希函数1.3 哈希冲突 二、闭散列2.1 数据类型2.2 成员变量2.3 默认成员函数2.…

【yy讲解PostCSS是如何安装和使用】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

深度学习:神经网络模型的剪枝和压缩简述

深度学习的神经网路的剪枝和压缩&#xff0c;大致的简述&#xff0c; 主要采用&#xff1a; network slimming&#xff0c;瘦身网络... 深度学习网络&#xff0c;压缩的主要方式&#xff1a; 1.剪枝&#xff0c;nerwork pruing&#xff0c; 2.稀疏表示&#xff0c;sparse rep…

KV260 BOOT.BIN更新 ubuntu22.04 netplan修改IP

KV260 2022.2设置 BOOT.BIN升级 KV260开发板需要先更新BOOT.BIN到2022.2版本&#xff0c;命令如下&#xff1a; sudo xmutil bootfw_update -i “BOOT-k26-starter-kit-202305_2022.2.bin” 注意BOOT.BIN应包含全目录。下面是更新到2022.1 FW的示例&#xff0c;非更新到2022.…

八数码问题——A*算法的应用(A-Star)

文章目录 1 问题描述2 启发式搜索3 A*算法3.1 参考网址3.2 是什么3.3 为什么A*算法适用于八数码问题3.4 A* 算法的基本框架 4 A* 算法如何解决八数码问题4.1 八数码状态的存储4.2 启发式函数4.3 构造目标状态元素位置的字典4.4 在二维列表中查找目标元素4.5 A* 算法主体4.6 路径…

Git 术语及中英文对照

完毕&#xff01;&#xff01;感谢您的收看 ----------★★历史博文集合★★---------- 我的零基础Python教程&#xff0c;Python入门篇 进阶篇 视频教程 Py安装py项目 Python模块 Python爬虫 Json Xpath 正则表达式 Selenium Etree CssGui程序开发 Tkinter Pyqt5 列表元组字…

Ubuntu22.04安装Anaconda

一、下载安装包 下载地址&#xff1a;https://www.anaconda.com/download#Downloads 参考&#xff1a;Ubuntu下安装Anaconda的步骤&#xff08;带图&#xff09; - 知乎 下载Linux 64-Bit (x86) installer 二、安装 在当前路径下&#xff0c;执行命令&#xff1a; bash Ana…