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.mzph.cn/pingmian/45000.shtml

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

相关文章

翻牌器单独设置前后缀样式

翻牌器单独设置前后缀样式 <template><div :style"[fontStyle,styleBackGroundColor]"><!-- <span style"color: #1d1d1d"> {{optionData}}</span>--><!-- 设置前缀样式 --><span class"prefix" …

怎么样的主食冻干算好冻干?品质卓越、安全可靠的主食冻干分享

当前主食冻干市场产品质量参差不齐。一些品牌过于追求营养数据的堆砌和利润的增长&#xff0c;却忽视了猫咪健康饮食的基本原则&#xff0c;导致市场上出现了以肉粉冒充鲜肉、修改产品日期等不诚信行为。更令人担忧的是&#xff0c;部分产品未经过严格的第三方质量检测便上市销…

Hadoop的HA模式搭建

准备三台虚拟机 bigdata007&#xff0c;bigdata008&#xff0c;bigdata009 1.前置工作 1.修改虚拟机的IP地址和hostname 2.配置集群中的ip映射&#xff08;/etc/hosts&#xff09; 192.168.111.57 bigdata007 192.168.111.58 bigdata008 192.168.111.59 bigdata0093.关闭虚拟…

武夷山细节决定成败抓质量求生存

在当今竞争激烈的市场环境中&#xff0c;细节决定成败&#xff0c;质量求生存的理念已成为企业发展的关键。蓝鹏测控科技有限公司&#xff0c;一家专业从事工业测量领域的高新技术企业&#xff0c;正是秉持这一理念&#xff0c;在工业测径仪领域取得了显著成就。 蓝鹏测控科技…

pandas修改时间索引报错处理

import pandas as pd import numpy as np import osdfpd.DataFrame(index[a,b,c],data{序列:[1,2,3]}) df.rename(index{a:a1},inplaceTrue) print(df) print(df.index.dtype)df1pd.DataFrame(index[2024-01-01,2024-01-02,2024-01-03],data{序列:[1,2,3]}) df1.rename(index{2…

Excel——REPLACE函数实现敏感信息打码

第一步&#xff1a; 以素材Excel文档为例。 在F2单元格中输入函数“REPLACE(B2,4,5,"*****")”&#xff0c;输入完毕后&#xff0c;按Enter键开始计算&#xff0c;并使用填充柄对其他区域进行填充。 这个函数的意思是&#xff1a;从第4位数字开始的5个数字用5个“…

医院门诊预约挂号小程序模板源码

医院门诊预约挂号小程序模板源码,主要有&#xff1a;绿色的医院住院办理&#xff0c;门诊预约挂号微信小程序页面模板。包含&#xff1a;办卡绑定、快速办理预约挂号、门诊缴费、住院服务、医院信息、个人中心、添加就诊人、找医生等等。 医院门诊预约挂号小程序模板源码

Elasticsearch:使用 Filebeat 从 Node.js Web 应用程序提取日志

本指南演示了如何从 Node.js Web 应用程序中提取日志并将其安全地传送到 Elasticsearch Service 部署中。你将设置 Filebeat 来监控具有标准 Elastic Common Schema (ECS) 格式字段的 JSON 结构日志文件&#xff0c;然后在向 Node.js 服务器发出请求时&#xff0c;你将在 Kiban…

Doris安装部署

Doris安装部署 1、 MPP概念2.Doris简要介绍 1、 MPP概念 MPP (Massively Parallel Processing)&#xff0c;即大规模并行处理&#xff0c;在数据库非共享集群中&#xff0c;每个节点都有独立的磁盘存储系统和内存系统&#xff0c;业务数据根据数据库模型和应用特点划分到各个节…

无人机之电池保养

一、充电时 1、推荐使用官方充电器和充电管家 2、充电时确保电池处于关闭状态 3、冷却后再充电理想充电温度22-28度 二、使用时 1、首次使用需要充电唤醒电池 2、切勿将电池耗尽过放容易造成电池鼓包 三、储存时 1、存放在环境干燥通风的地方 2、不使用时每两个月充一…

谷粒商城实战-25-分布式组件-SpringCloud Alibaba-Nacos配置中心-加载多配置集

文章目录 一&#xff0c;拆分配置集二&#xff0c;配置文件中配置多配置集1&#xff0c;引用多配置集2&#xff0c;验证 三&#xff0c;多配置集总结1&#xff0c;使用场景2&#xff0c;优先级 这一节介绍如何加载多个配置集。 大多数情况下&#xff0c;我们把配置全部放在一个…

C语言 结构体和共用体——对结构体的操作

目录 如何访问结构体的成员&#xff1f; 结构体变量的赋值操作 结构体变量的取地址值操作 如何访问结构体的成员&#xff1f; 结构体变量的赋值操作 结构体变量的取地址值操作

如何为谷歌seo打好基础?

选择获取一个合适的域名&#xff0c;选择一个好的域名是 SEO 成功的第一步。以下是一些建议&#xff1a; 域名名称&#xff1a;要短小易记&#xff0c;不要强行插入关键词。最好用你的公司名称&#xff0c;避免使用连字符或特殊字符。用户在输入一个复杂的域名时容易出错&…

Ozon俄罗斯哪些产品热销中?Ozon7月市场热卖趋势放送

Ozon俄罗斯哪些产品热销工具&#xff1a;D。DDqbt。COm/74rD 据Ozon数据&#xff0c;2023年&#xff0c;在自提服务方面&#xff0c;Ozon投资了100亿扩展自提网络&#xff0c;自提点数量激增至超过5万个&#xff0c;是之前的2.6倍。 物流基础设施方面&#xff0c;Ozon在仓库建…

树莓派4B_OpenCv学习笔记19:OpenCV舵机云台物体追踪

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1&#xff1a; Python 版本3.7.3&#xff1a; ​​ 今日学习&#xff1…

【数据结构】排序——快速排序

前言 本篇博客我们继续介绍一种排序——快速排序&#xff0c;让我们看看快速排序是怎么实现的 &#x1f493; 个人主页&#xff1a;小张同学zkf ⏩ 文章专栏&#xff1a;数据结构 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 ​ 目录 …

前端JS特效第30波:jquery图片列表按顺序分类排列图片组效果

jquery图片列表按顺序分类排列图片组效果&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> &…

Profibus协议转Profinet协议网关模块连接智能电表通讯案例

一、背景 在工业自动化领域&#xff0c;Profibus协议和Profinet协议是两种常见的工业通讯协议&#xff0c;而连接智能电表需要用到这两种协议之间的网关模块。本文将通过一个实际案例&#xff0c;详细介绍如何使用Profibus转Profinet模块&#xff08;XD-PNPBM20&#xff09;实…

启航IT之旅:为新生绘制的学习路线图

随着七月的热浪悄悄席卷而来&#xff0c;各地高考成绩陆续放榜&#xff0c;对于刚迈过高考这座独木桥的你们&#xff0c;这不仅仅是一个故事的终章&#xff0c;更是另一段冒险的序曲。特别是那些心中有一团IT火焰燃烧的少年们&#xff0c;暑假的钟声已经敲响&#xff0c;是时候…