C++相关概念和易错语法(18)(array、模板)

1.array

(1)普通数组的劣势

当我们直接越界修改值时,一般会在编译时就被拦截

但是越界访问,只要访问距离不算特别大,那么也可以越界访问

当我们不直接越界修改或访问,间接去访问和修改能越界非常远

这里的i直到342才被拦截下来,这足以反映出普通的数组是有一定的风险的,在有的情况下会导致数据被篡改,下面以VS编译器为例,在VS中栈区变量由低地址向高地址存,所以向上越界修改会影响其它变量的值,如果这个值很重要,那么使用普通数组就很危险,我们需要一种更安全的方式,这就是array。

(2)array检查方式和普通数组的区别

array是用类封装静态数组,其中类最大的好处是可以重载operator[],可以在重载函数里面添加断言检查等,每一次调用都会进行检查是否越界,如果越界会直接报错。

而普通数组是在数组界外设置了一些标志位,如果标志位被访问或者修改了就会报错,但整体上而言,我们能够进行不同程度上的越界访问和修改,依然有风险,就像上面展示的那样。

当我们使用array时,就能很好地避免这个问题。

但是arrary不如使用vector,因为在处理上和vector几乎没什么区别,但array是在栈区开辟,而vector是在堆区开辟空间,堆区的空间要远远大于栈区的空间。所以推荐使用vector,其相较于普通数组的优势和array的一模一样。

2.非类型模板参数

定义模板时要传模板参数,其中有类型模板参数,如class T参数接受的就是一个类型(如int、double),类型模板参数实施例化出函数或类的关键,也是模板的精髓所在。但除此之外,在模板参数处还可以定义非类型模板参数,如int a,char b接收的就是值而非类型。

利用非类型模板参数定义的是常量而不是变量,不能有任何修改操作

非类型模板参数在C++20前只能是整型家族的,如char、size_t、int等,而指针、double类型是不支持的

切换到C++20,就可以使用内置类型作为非类型模板参数了,包括内置类型的指针、double等

设置界面如下:

但是需要注意的是,C++20后仍不支持自定义类型作为非类型模板参数,像string这些都不支持

3.模板的按需实例化

模板有个特点是按需实例化,在我们没有调用这个模板类或模板函数时,它是不会实例化的。这意味着编译器只会检查最基本的语法错误,而不会去检查里面的细节

(1)普通函数和模板的检查严格程度的比较

我们来对比一下

对于普通函数,就算我们不去调用它,编译器在编译阶段是会比较深入的去检查的,这里由于"a"是常量字符串,不能修改,所以交给arr的指针不能*arr,因此要用const char*,所以报错了。这里同时也要注意1和3是有区别的,3是单独在栈区开了一块空间,所以不会报错,而1并没有开空间。

而对于模板来说,编译器的检查就很弱了。

在这里我们可以看到,char* arr = "a"本身就是个错误写法但没有报错。包括Fun()里面的N++也是经典的语法错误,但这些在编译阶段都不会被检查出来,只有在触发了很离谱的语法错误(忘写分号等)才会检查出来,而且这个时候的报错极为难看。

记住下面这种报错原因,等会有用

只有当实例化后我们才能检查到错误,就算类被实例化了,如果里面有模板函数,在被调用前这些模板函数也不会实例化,这就是按需实例化。

(2)typename声明

刚刚第二张模板类报错是因为arr b = "a"犯了严重的语法错误。即arr不是类型。看上去这个错误很荒谬,但是这引出了一个新的问题,如下图:

究竟是什么导致了错误,我们已经知道,模板类实例化之前检查语法很弱,但这里就有一个显然的语法错误,那就是Test<T>::iterator it中iterator究竟是静态成员变量还是一个类型呢?

这就跟我最开始提到的arr b = "a"出现了同样的问题,为了避免歧义,我们需要在最前面声明它是一个类型而非静态成员函数。

但是这里需要注意的是这是在模板的前提下才需要这么写,如果已经实例化出了Test<int>,这种语法就不会导致歧义,编译器能很轻松的判断这是一个类型

4.特化

(1)全特化

函数模板的特化和类模板的特化用法上都很好理解,实际就是针对一些很特殊的类型做特殊的处理,注意要写template<>,这其实是声明这是个模板,没有模板参数就不写,在函数名或类名后要写实例化的类型。

但这里需要特别注意的是全特化指针或引用时,要注意全特化的函数的传参要和模板函数的参数匹配

下面这种写法为什么有问题?

原因在于const T中const修饰的是ptr,即ptr不能修改,同理,ref也不能修改。而const int*的意思是*ptr而不是ptr本身,ref也是如此,所以const的位置要变,下面这种才是正确写法

在优先级上,如果已经定义了普通函数,就会最优先调用普通函数,其次找特化,如果实在没有,就会去实例化模板函数。一般来说特化用的不多,因为像刚才那样的坑很难理解,所以如果真要特殊处理,直接写普通函数是最好的选择。

(2)偏特化(只能针对类)

偏特化(半特化)是针对某一个模板参数而非全部模板参数进行特殊化处理。针对的方式可以是类型,也可以是某种修饰,如*、&等

先介绍一个简单的,就是针对某一个或几个而非全部模板参数的特殊处理。在写法上和全特化很像,我们可以认为全特化是偏特化的一种特殊情况。

但是注意偏特化不能针对函数,只能在类上使用偏特化

偏特化中还有一种就是针对某种修饰方式进行特殊处理

看下面这段代码


#include <iostream>
using namespace std;template<class T1, class T2>
class test
{
public:test(){cout << "test" << endl;}
};template<class T1, class T2>
class test<T1*, T2&>
{
public:test(){cout << "T1 = " << typeid(T1).name() <<  endl << "T2 = " << typeid(T2).name() << endl;}
};int main()
{test<int, char>();test<int*, int&>();return 0;
}

我们发现当实例化是加上*或者&时,当实例化类型对上时就会走偏特化。而对于T1和T2而言还能反推。

需要注意的是,const也可作为修饰成分并严格要求匹配才会调用偏特化


偏特化的好处在于能针对处理的类型更灵活,并且通过修饰的类型能推导原类型,我们又可以通过这个原类型加一些修饰得到其它修饰的类型,在代码中选择更多。

5.编译模板

模板是不能声明和定义分到两个文件中的。

原因在于如果对于普通函数,虽然声明定义分离,但是定义处的函数代码仍然完整,可以顺利编译,链接时进符号表,如果声明定义没有分离,那在编译阶段就能进符号表。当调用函数时,会直接到符号表中找,效率很高。

但对于模板函数编译器是不会编译的,因为不知道编译成什么。如果让模板去遍历文件找实例化,大型项目文件多的情况效率大大降低,不会这么做。当编译器遇到调用模板函数时,就会实例化声明,但这个声明找不到定义,定义处直接被跳过编译了。而如果在同一文件或在定义处显式声明实例化类型,就能在第一时间实例化。

总结一下:唯一的方案是模板不要分离文件,声明处知道实例化成什么但没定义,定义处有定义但不知道实例化成什么

6.模板缺陷:编译时间变长,错误信息凌乱

7...cc就是.cpp,而.hpp是.cpp和.h结合,根据模板的性质,我们可以将模板写在.hpp文件中

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

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

相关文章

FPGA上板项目(一)——点灯熟悉完整开发流程、ILA在线调试

目录 创建工程创建 HDL 代码仿真添加管脚约束添加时序约束生成 bit 文件下载ILA 在线调试 创建工程 型号选择&#xff1a;以 AXU9EG 开发板为例&#xff0c;芯片选择 xczu9eg-ffvb1156-2-i 创建 HDL 代码 注意&#xff1a;由于输入时钟为 200MHz 的差分时钟&#xff0c;因此…

嵌入式开发过程中,常见报错以及解决方法

编写不易&#xff0c;仅供学习&#xff0c;参考谢谢&#xff0c;还望理解。 #常见报错 文件最后一行没有新行 翻译&#xff1a;文件的最后一行结束时没有新行 解决方法&#xff1a;定位到&#xff0c;提示报错的 .h 文件 报错行 &#xff0c;加上一个新行 函数定义时与官方提…

Vue中实现在线画流程图实现

概述 最近在调研一些在线文档的实现&#xff0c;包括文档编辑器、在线思维导图、在线流程图等&#xff0c;前面的文章基于语雀编辑器的在线文档编辑与查看实现了文档编辑器。在本文&#xff0c;分享在Vue框架下基于metaeditor-mxgraph实现在线流程图。 实现效果 实现 1. 添加…

Python酷库之旅-第三方库Pandas(017)

目录 一、用法精讲 41、pandas.melt函数 41-1、语法 41-2、参数 41-3、功能 41-4、返回值 41-5、说明 41-5-1、宽格式数据(Wide Format) 41-5-2、长格式数据(Long Format) 41-6、用法 41-6-1、数据准备 41-6-2、代码示例 41-6-3、结果输出 42、pandas.pivot函数 …

休息时间c++

题目描述 小杨计划在某个时刻开始学习&#xff0c;并决定在学习k秒后开始休息。 小杨想知道自己开始休息的时刻是多少。 输入 前三行每行包含一个整数&#xff0c;分别表示小杨开始学习时刻的时h、分m、秒s(h&#xff0c;m&#xff0c;s的值符合1≤h≤12,0≤m≤59,0≤s≤59)…

SpringBoot新手快速入门系列教程七:基于一个低配centoos服务器,如何通过宝塔面板部署一个SpringBoot项目

1&#xff0c;如何打包一个项目 通过IDEA自带的命令行&#xff0c;执行 ./gradlew clean build 2&#xff0c;检查生成的JAR文件 进入 build/libs 目录&#xff0c;你应该会看到一个类似 helloredis-0.0.1-SNAPSHOT.jar 的文件。 3&#xff1a;运行生成的JAR文件 你可以在…

JupyterNotebook中导出当前环境,并存储为requirements.txt

​使用Anaconda管理Python环境时&#xff0c;可以轻松地导出环境配置&#xff0c;以便在其他机器或环境中重新创建相同的环境。可以通过生成一个environment.yml文件实现的&#xff0c;该文件包含了环境中安装的所有包及其版本。但是&#xff0c;常常在一些课程中JupyterNotebo…

韦东山嵌入式linux系列-LED驱动程序

之前学习STM32F103C8T6的时候&#xff0c;学习过对应GPIO的输出&#xff1a; 操作STM32的GPIO需要3个步骤&#xff1a; 使用RCC开启GPIO的时钟、使用GPIO_Init函数初始化GPIO、使用输入/输出函数控制GPIO口。 【STM32】GPIO输出-CSDN博客 这里再看看STM32MP157的GPIO引脚使用…

逻辑回归中的损失函数

目录 一、损失函数介绍&#xff1a;二、简化上述损失函数&#xff1a; 一、损失函数介绍&#xff1a; 与回归问题成本函数不同的是&#xff0c;逻辑回归模型&#xff08;解决分类问题&#xff09;的成本函数在获得损失J的时候不再用真实值y与预测值y^的差值计算损失&#xff0…

Python面试宝典第11题:最长连续序列

题目 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1&#xff1a; 输入&#xff1a;nums [100,4,200,1,3,2] 输出&#xff1a;…

STM32智能电网监控系统教程

目录 引言环境准备智能电网监控系统基础代码实现&#xff1a;实现智能电网监控系统 4.1 数据采集模块 4.2 数据处理与分析 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;电网监控与优化问题解决方案与优化收尾与总结 1. 引言 智能电网监控系统通过S…

学习网络的第一步:全面解析OSI与TCP/IP模型

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! Hello,大家好!我是你们的好朋友小米。今天我们来聊一聊网络基础知识中的重量级选手——OSI模型和TCP/IP模型!网络的世界就像一个巨大的迷宫,而这两个…

肯尼亚PVoC认证

一、肯尼亚PVoC认证介绍 为了向肯尼亚消费者保证&#xff0c;他们购买的进口商品的安全和质量&#xff0c;并保护肯尼亚制造商免受不公平竞争&#xff0c;肯尼亚标准局&#xff08;KEBS&#xff09;是肯尼亚政府的一个法定机构&#xff0c;实施了“出口肯尼亚出口验证&#xff…

【源码开源】C#桌面应用开发:串口调试助手

c#桌面应用开发 1、环境搭建和工程创建&#xff1a;参照番茄定时器项目 工程创建参照 2、界面布局设计 3、具体功能函数 &#xff08;1&#xff09;端口扫描&#xff1a; private void btn_com_scan_Click(object sender, EventArgs e){//端口号扫描ReflashPortToComboBox(…

赤壁之战的烽火台 - 观察者模式

“当烽火连三月&#xff0c;家书抵万金&#xff1b;设计模式得其法&#xff0c;千军如一心。” 在波澜壮阔的三国历史长河中&#xff0c;赤壁之战无疑是一场改变乾坤的重要战役。而在这场战役中&#xff0c;一个看似简单却至关重要的系统发挥了巨大作用——烽火台。这个古老的…

基于ssm的图书管理系统的设计与实现

摘 要 在当今信息技术日新月异的时代背景下&#xff0c;图书管理领域正经历着深刻的变革&#xff0c;传统的管理模式已难以适应现代社会的快节奏和高要求&#xff0c;逐渐向数字化、智能化的方向演进。本论文聚焦于这一转变趋势&#xff0c;致力于设计并成功实现一个基于 SSM&…

在HTTP协议中常见的Token类型

在HTTP协议中&#xff0c;常见的Token类型主要有以下几种&#xff1a; Bearer Token&#xff1a;最常见的类型&#xff0c;用于OAuth 2.0认证&#xff0c;通过Authorization头传递&#xff0c;格式为Bearer <token>。更多请阅读&#xff1a;JWK和JWT 学习-CSDN博客 Basi…

【数据结构】09.树与二叉树

一、树的概念与结构 1.1 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 根结点&#xff1a;根…

应变与几何方程——弹性力学

变形协调方程 正应变的表达式&#xff1a;切应变的表达&#xff1a; 考虑坐标位移移动造成的增量 应变——考虑物体的变形的剧烈程度 正应变——微元线段长度的变化 剪应变——两微元所夹角度的变化 正应变——拉伸为正&#xff0c;压缩为负 剪应变——夹角减小为正&#x…

删除有序数组中的重复项

26. 删除有序数组中的重复项 - 力扣&#xff08;LeetCode&#xff09; 快慢指针&#xff0c;慢的指针去追赶快的指针&#xff0c;相等时也就是追到时&#xff0c;快指针移动向前 class Solution { public:int removeDuplicates(vector<int>& nums) {int s 1, q 1;i…