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" …

【面试题】MySQL(第四篇)

1.详细说一下一条 MySQL 语句执行的步骤 Server 层按顺序执行 SQL 的步骤为&#xff1a; 客户端请求 -> 连接器&#xff08;验证用户身份&#xff0c;给予权限&#xff09; 查询缓存&#xff08;存在缓存则直接返回&#xff0c;不存在则执行后续操作&#xff09; 分析器&a…

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

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

高效的采购管理系统,提升企业采购效能利器

在当今全球化和竞争激烈的商业环境中&#xff0c;企业如何有效管理和优化采购过程&#xff0c;直接影响到企业的运营成本和市场竞争力。传统的手工或半自动化采购管理方式已经难以满足现代企业的需求&#xff0c;因此&#xff0c;越来越多的企业开始转向高效的采购管理系统&…

深度优先算法-DFS(算法篇)

算法之深度优先算法 深度优先算法(DFS) 概念&#xff1a; 深度优先算法(DFS)跟BFS算法一样是用于遍历图的算法&#xff0c;但是DFS并不像BFS算法一样&#xff0c;它搜索出来的路径不具有最短性&#xff0c;并且dfs算法类似于枚举&#xff0c;因此DFS算法一般用于求出问题的所…

雅思词汇及发音积累 2024.7.11

计算机房 computer lab 计算机房 mainframe 主机 monitor 屏幕 screen 键盘 keyboard 键盘 mouse 鼠标 memory 内存 loudspeaker 扬声器 printer 打印机 scanner 扫描仪 photocopier/copier 复印机 laser printer 激光打印机 software programme 程序 viruses /ˈvaɪərəsɪz…

linux ssh 远程执行shell 获取返回值

#!/bin/bashSCRIPTcd / && lsresult$(ssh -o StrictHostKeyCheckingno root10.204.0.1 $SCRIPT) echo "result: $result"或者下面# 远程服务器的IP地址或主机名 HOSTremote_host # 远程服务器的用户名 USERusername # 远程执行的脚本 SCRIPT/path/to/remote/…

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、不使用时每两个月充一…

华为机考真题 -- 查找众数及中位数

题目描述: 1.众数是指一组数据中出现次数量多的那个数,众数可以是多个 2.中位数是指把一组数据从小到大排列,最中间的那个数,如果这组数据的个数是奇数,那 最中间那个就是中位数,如果这组数据的个数为偶数,那就把中间的两个数之和除以 2,所 得的结果就是中位数 3.查找…

qt 绘制一个自定义的控件

1.qt 绘制一个自定义的控件 要点 QPainter painter(this); painter.setPen(Qt::NoPen); painter.setBrush(Qt::red); painter.drawRect(rect()); / 在 Qt 中绘制一个自定义的控件通常涉及几个步骤。下面是一个基本的指南&#xff0c;说明如何创建…

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

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

vite build 打包错误提示 EBUSY: resource busy or locked, copyfile ‘D:\gtv-web

EBUSY: resource busy or locked, copyfile D:\gtv-web 报错解释&#xff1a; 当前应用正在运行中&#xff0c;把应用进程关掉即可 EBUSY: resource busy or locked 错误表明尝试使用的资源正被另一个进程占用或锁定。在这种情况下&#xff0c;copyfile 命令试图复制文件到指…

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

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