C++中的new和模版

前言

        随着C++的学习,讲了C++的发展过程、流插入、流提取、函数缺省值、类与构造等等。接下来学习C++很方便的 玩意,函数模版。函数模版就像是模具一样,C++会自动用模版编译出合适的函数供程序员使用。以前不同类型相同操作的函数都能通过函数模版,只写一个来解决。这么说来,怪不得祖师爷会写出函数重载这样的优化。因为如此,函数模版大有作用。

        在此之前,上一节中提到的新增操作符new和delete。这两个操作符也是在堆上申请空间操作符,这一节会回顾一下,并进行补充。

一、new和delete

1、简介

        new和delete是C++中新增的关键字,new用来申请堆上的空间,delete用来释放堆上的空间。在C语言中我们学过了3个函数,分别是“malloc”“ralloc”“free”,前两个用来申请空间,free用来释放空间。

        既然C语言中已经有了申请空间的函数,为什么C++中又单独开发出来一套系统来申请空间呢?接下来就来聊聊他们之间的区别吧。

2、malloc/free与new/delete的区别:

(1)malloc/free是函数,new/delete是操作符。

(2)malloc申请空间就只是申请空间不会初始化,new会申请空间并初始化空间。

(3)malloc需要手动计算申请空间的大小,new能够通过类型自动计算需要申请大小。

(4)malloc申请空间失败会返回NULL,new申请空间失败不会返回NULL但是需要捕获异常(这里需要用到try/catch)。

(5)malloc只是开空间,free只会释放空间、new会调用构造函数初始化空间,delete会调用析构函数释放空间。

3、实际举例

        如果正常的使用new和delete,也就是说配套使用,方法如下:

#include <iostream>using namespace std;class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 0)->" << _a <<endl;}~A(){cout << "~A()->" << _a << endl;}
private:int _a;
};int main()
{A* exp = new A;delete exp;exp = new A[4]{1,2,3,4};delete[] exp;exp = nullptr;return 0;
}

        如举例所示,在new后面接上“类型”就能够直接开辟一个类的空间,释放空间接delete和它的指针。如果需要开辟多个空间就像数组一样在new后面接上“类型[]”,释放空间就需要接“delete[]”和它的指针。同时如果想修改初始化中的成员可以增加“{}”,里面写变量。那么调用构造的时候会直接使用。

        但是为什么不直接用“delete”而是需要增加“delete[]”?这是因为用new申请多个空间的时候会在所开空间前额外开4个字节的空间用来记录调用构造和析构函数的次数,方便处理。这个时候使用delete会出错,程序会直接结束。因为多开了4字节。到了现在C++的进步,如果不写析构函数,那么优化做的比较多的编译器就不会多生成这4个字节“delete”也能够使用。

        如果将类“A”的析构函数去掉,那么使用“delete”释放空间也是可行的。例如:

class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 0)->" << _a <<endl;}private:int _a;
};

        另外,malloc/free也可以和new/delete混用,但是不会调用构造和析构函数,如果类里面有申请空间,就不能使用例如:

class B
{
public:B(){_b = new int(0);}~B(){delete _b;}
private:int* _b;
};

        这是因为malloc/free不会调用析构和构造去释放申请的空间,造成内存泄漏,所以最好将new和delete配套使用。

4、练习题举例

求1+2+3+...+n_牛客题霸_牛客网求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、swit。题目来自【牛客题霸】icon-default.png?t=N7T8https://www.nowcoder.com/practice/7a0da8fc483247ff8800059e12d7caf1?tpId=13&tqId=11200&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

        描述

        求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

        数据范围: 0<𝑛≤2000<n≤200
        进阶: 空间复杂度 𝑂(1)O(1) ,时间复杂度 𝑂(𝑛)O(n)

        这道题就能用到我们类的算法,建立全局变量然后通过类的创建来修改它,只需要用new创建n个类的空间,然后自动调用构造函数进行累加,这样就能计算出和:

class Sum
{
public:Sum(){i++;ret += i;}static void Reset(){i = 0;ret = 0;}static int i;static int ret;
};int Sum::i = 0;
int Sum::ret = 0;class Solution {
public:int Sum_Solution(int n) {Sum::Reset();Sum* ps = new Sum[n];delete[] ps;return Sum::ret;}
};

二、模版

1、函数模版

1.1、简介

        函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。

        它的出现虽然对于编译器来说增加了开销,但是却节省了程序员的开销,让程序员写一个功能就能一劳永逸。

1.2、举例使用

        在讲到C语言函数的时候,我们学到的有加法函数,就是将两个数加起来,最后变成一个数返回。那么这里我们也用这个函数举例。

template<class T>
T Add(T& n1, T& n2)
{return n1 + n2;
}

        这里的“tempelate”是C++中新增的关键字,这个关键字能够用来定义模版变量的类型。在上述函数中,“n1”和“n2”是同一种类型,他们都属于类型“T”。这里的“T”可以根据需要取名字,就和类一样。这个类型“class”也可以使用“typename”,所以这个函数用以下写法也是一样的:

template<typename T1>
T1 Add(T1& n1, T1& n2)
{return n1 + n2;
}

        在函数的使用方面分为两种方法,第一种是推导实例化、另一种是显示实例化。接下来会在例子中主要说明两种实例化的不同操作方式。模版函数就采用上面写的“Add”函数:

#include <iostream>
using namespace std;template<class T>
T Add(T n1, T n2)
{return n1 + n2;
}int main()
{int a1 = 10, a2 = 20;double d1 = 10.1, d2 = 20.2;// 推导实例化cout << Add(a1, a2) << endl;cout << Add(a1, (int)d1) << endl;cout << Add((double)a1, d1) << endl << endl;// 显示实例化cout << Add<int>(a1, d1) << endl;cout << Add<double>(a1, d1) << endl;return 0;
}

        推导实例化就是模版的参数程序员不给出,由传入函数的参数以及编译器的推导决定。相反显示实例化就是程序员固定了模版的类型,计算机直接将这个类型交给模版就行了。注意返回值无法影响编译器的推导,只有输入的形参才行。上述代码的结果如下:

        请注意,如果使用推导实例化就不能让编译器搞不清楚变量实例化成什么类型。如下传法都是错误的:

int main()
{int a1 = 10, a2 = 20;double d1 = 10.1, d2 = 20.2;// 推导实例化cout << Add(a2, d2) << endl;cout << Add(a1, d1) << endl;cout << Add(a1, d2) << endl << endl;return 0;
}

        编译器会觉得,到底是“int”还是“double”呢?就直接报错退出了。所以这里建议使用显示实例化,编译器也不含糊,不容易出错。

2、类模版

        除了函数能够使用模版之外,类也能使用模版。他们的作用都是相同的,减少程序员的代码量。使用方法也类似。所以这里就直接举例了。

2.1、使用举例

        比如说我们需要建立一个可以装不同数据的栈,那么我们也可以用到函数模版:

namespace lcs
{template<typename T>class Stack{public:Stack(int n = 4):_array(new T[n]),_capacity(n),_size(0){}~Stack(){delete[] _array;_array = nullptr;_size = _capacity = 0;}void push(const T& x){if(_size == _capacity){T* tmp = new T[_capacity * 2];memcpy(tmp, _array, sizeof(T) * _size);delete[] _array;_array = tmp;_capacity *= 2;}_array[_size++] = x;}void pop(){if(_size != 0){--_size;}}T top(){if(_size != 0){return _array[_size - 1];}else{return T(0);}}bool empety(){return !_size;}private:T* _array;size_t _capacity;size_t _size;};
}int main()
{lcs::Stack<int> st_int;lcs::Stack<double> st_double;st_int.push(1);st_int.push(2);st_int.push(3);st_int.push(4);cout << st_int.top() << endl;st_int.pop();st_int.pop();st_int.pop();cout << st_int.top() << endl;st_double.push(1.123);cout << st_double.top() << endl;return 0;
}

        这样我们的栈也能够使用了,和函数不同的是类模板都需要显示实例化,请注意。

        这里我也用到了命名空间,这样就不会和库里的函数重叠。运行后无误:

        创建了两种栈“int”和“double”的,同时输入输出一些栈内元素,输出上和代码预期相同。首先入4个数到“int”栈,然后取栈顶元素输出。然后从“int”栈中删除3个再次输出栈顶元素。随后输入一个元素到“double”栈,然后输出它。

        在模版之中的类型也可以是自定义类型,但相应的就需要写更多的代码来确保运行。

作者结语

        到这里C++中的模版也就告一段落了,学习本节我觉得最大的作用就是为接下来学习stl标准库做准备,当然标准库的介绍分一节还讲不完。接下来可能会分多次博客进行细致讲解,或者偷个懒,全部写完总结之后写到一篇里一次发出来。又是一项大工程了,吐血。

        要是博客也有个模版就好了,我也一套然后计算机帮我整理,哈。我愿称为计算机万能。接下来其实还挺简单的,虽然我还没学到但是我预习了。和这里模版类中自己写的类差不多的写法就行。之前也学过很多操作符重载,就是这些。然后就是通用的一些函数,包装一下就能直接用了。

         除了string还要重新学习C++的顺序表和链表和二叉树和哈希表。我故意这么写的,主要是想起来还很多。干啦兄弟们!

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

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

相关文章

js实现数组的下标为n的对象后面新增一条对象

前言&#xff1a; js实现数组的下标为n的对象后面新增一条对象 实现方法&#xff1a; arr.splice(1, 0, obj); splice 参数1: 数组里面的第几个元素&#xff0c;你希望在第几个对象后面新增参数2: 0 表示不删除任何元素参数3: 插入的新对象 let arr [{},{},{},{}] let obj…

书籍数组中的最长连续序列(4)0716

题目 给定无序数组arr&#xff0c;返回其中最长的连续序列的长度。 一些定义&#xff1a; 数组 子数组&#xff1a; 一个或连续多个数组中的元素组成一个子数组。子数组最少包含一个元素。 对于大小为n的数组&#xff0c;有n*(n1)/2个非空子数组。 子序列&#xff1a;子序…

Android Display Graphics #从Activity看surface的创建(1)

如果图片链接失败&#xff0c;请扫码查看文章详情。 Android Display Graphics系列文章-汇总 系列文章请扫关注公众号&#xff01; 创建Activity Activity是Android系统的应用组件&#xff0c;一般情况下&#xff0c;开发者显示的内容是通过Activity展示的。比如 使用Androi…

pdf文件太大如何压缩变小一点?这几种压缩方法很实用!

pdf文件太大如何压缩变小一点&#xff1f;在日常工作与学习的海洋里&#xff0c;我们时常遭遇PDF文件的“重量级”挑战&#xff0c;这些体积庞大的文档&#xff0c;如同数字世界的巨石&#xff0c;不仅吞噬着宝贵的存储资源&#xff0c;还拖慢了处理速度&#xff0c;影响设备性…

单链表算法 - 链表的回文结构

链表的回文结构_牛客题霸_牛客网对于一个链表&#xff0c;请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法&#xff0c;判断其是否为。题目来自【牛客题霸】https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa思路1: /* struct ListNode {int val;st…

探索Sklearn中的分层聚类:数据的智能分组艺术

探索Sklearn中的分层聚类&#xff1a;数据的智能分组艺术 在数据科学领域&#xff0c;聚类是一种将数据点分组成多个簇的无监督学习方法&#xff0c;目的是使得同一簇内的数据点相似度高&#xff0c;而不同簇之间的数据点相似度低。分层聚类&#xff08;Hierarchical Clusteri…

.net dataexcel 脚本公式 函数源码

示例如: ScriptExec(""sum(1, 2, 3, 4)"") 结果等于10 using Feng.Excel.Builder; using Feng.Excel.Collections; using Feng.Excel.Interfaces; using Feng.Script.CBEexpress; using Feng.Script.Method; using System; using System.Collections.Gen…

MATLAB R2023b下载安装教程汉化中文版设置

MATLAB R2023b下载安装教程汉化中文版设置 Matlab 是一款功能强大的商业数学软件 Matlab&#xff08;Matrix Labortory&#xff09;即矩阵实验室&#xff0c;它在数值计算、数据分析、算法开发、建模与仿真等众多领域都发挥着重要作用。 Matlab 具有以下显著特点和优势&…

TYPE-C接口PD取电快充协议芯片ECP5701:支持PD 2.0和PD 3.0(5V,9V,12V,15V,20V)

随着智能设备的普及&#xff0c;快充技术成为了越来越多用户的刚需。而TYPE-C接口作为新一代的USB接口&#xff0c;具有正反插、传输速度快、充电体验好等优点&#xff0c;已经成为了快充技术的主要接口形式。而TYPE-C接口的PD&#xff08;Power Delivery&#xff09;取电快充协…

MySQL学习记录 —— 이십삼 MySQL服务器文件系统(3)

文章目录 1、数据字典2、系统表各种系统表 Mysql Schema是⼀个系统库&#xff0c;表中存储了MySQL服务器运行时所需的信息。广义上&#xff0c;mysql schema包含存储MySQL程序基本数据的数据字典和用于其他操作目的的系统表。数据字典表和系统表位于数据目录下一个名为mysql.ib…

角点检测及MATLAB实现

一、角点简介 角点通常指的是两条直线构成角时的交点。‌在更广泛的应用中&#xff0c;‌角点这一概念也被扩展到数字图像处理领域&#xff0c;‌其中角点被定义为图像中物体轮廓线的连接点&#xff0c;‌这些点在某方面属性特别突出&#xff0c;‌即在某些属性上强度最大或者最…

股票行情接口,接入方法对比

Websocket和Http接入方式区别 股票行情数据对投资者和交易员而言极其重要。借助股票行情接口&#xff0c;能够便捷获取实时股票行情数据&#xff0c;从而及时做出决策。股票行情接口通常分为两种&#xff0c;分别是 WebSocket 和 http。 通过 WebSocket 能够获取逐笔的股票 t…

为什么不要碰自媒体

要是失业了&#xff0c;搞自媒体&#xff0c;可行吗&#xff1f;毫无希望&#xff01; 如今的自媒体早卷得不成样子了&#xff0c;很难再有机会&#xff0c;根本原因在于几乎没有增量用户的同时&#xff0c;存量用户也不再有剩余时间&#xff0c;全量用户的时间早已被几个自媒…

空间计算开发:Volu的集成开发工具包

在空间计算技术迅速发展的今天,VR和AR项目的开发需求日益增长。Volu,一个面向空间计算赛道的开发者工具,正致力于简化这一过程。本文将深入探讨Volu如何通过其集成环境,为开发者提供一站式的解决方案。 一、定位:空间计算的得力助手 Volu定位为一个专为空间开发设计的集…

verilog基础语法入门

文章目录 前言一、模块定义1. 模块声明2. 端口定义3. 信号类型声明4. 逻辑功能定义 二、运算符与表达式1. 算术运算符2. 逻辑运算符3. 位运算符4. 关系运算符5. 等式运算符6. 缩减运算符7. 移位运算符8. 条件运算符9. 位拼接运算符 三、语句1. 赋值语句2. 块语句3. 条件语句4. …

麦芒30全新绽放,中国电信勾勒出AI手机的新方向

高通总裁兼CEO克里斯蒂亚诺阿蒙曾在媒体采访时表示&#xff1a;2024年将成为全球AI手机元年&#xff0c;生成式AI正在“非常快”的进入手机。 把大模型装进手机&#xff0c;由此成了智能终端演进的新方向。三星、华为、OPPO、小米等品牌动作频频&#xff0c;纷纷抢滩AI手机市场…

深入理解 Vue.js 的生命周期:从创建到销毁

Vue.js 是一个渐进式的 JavaScript 框架&#xff0c;广泛用于构建用户界面。理解 Vue.js 的生命周期不仅有助于优化性能&#xff0c;还能帮助开发者更好地管理组件的状态和行为。在这篇博客中&#xff0c;我们将深入探讨 Vue.js 的生命周期&#xff0c;并通过代码示例来展示每个…

HarmonyOS NEXT学习——@Styles、@Extend、stateStyles

Styles装饰器 定义组件重用样式 仅支持通用属性和通用事件不支持参数可以定义全局和组件内使用&#xff0c;全局使用需要加function // 全局 Styles function functionName() { ... }// 在组件内 Component struct FancyUse {Styles fancy() {.height(100)} }组件内Styles的优…

Pliops XDP与国产SSD大普微合作

以色列的Pliops公司开发出了XDP&#xff08;Extreme Data Processor&#xff09;AccelKV&#xff0c;这是一种基于键值存储技术的PCIe卡&#xff0c;能够为诸如RocksDB和RAID等应用从主机x86服务器卸载并加速底层存储堆栈处理。Pliops最近与Hammerspace建立了合作关系&#xff…

探索数据的隐藏维度:使用Scikit-Learn进行特征交互性预测

探索数据的隐藏维度&#xff1a;使用Scikit-Learn进行特征交互性预测 在机器学习中&#xff0c;特征交互性是指不同特征之间可能存在的复杂关系&#xff0c;这些关系对预测结果有着重要影响。Scikit-Learn&#xff08;简称sklearn&#xff09;&#xff0c;作为Python中广受欢迎…