C++之内存管理及函数模版

news2025/2/22 19:59:11

C++中的内存管理机制和C语言是一样的,但在具体内存管理函数上,C语言malloc已经无法满足C++面向对象销毁的需求,于是祖师爷在C++中新增了一系列内存管理函数,即 newdelete 著名段子:如果你还没没有对象,那就尝试 new 一个吧。

一、内存分布

在内存中存在五大分区,各个分区都各司其职,比如我们耳熟能详的栈区,堆区,静态区。

 

二、C语言的三种动态内存管理的函数

malloc:申请指定大小的空间

int* pi = (int*)malloc(sizeof(int) * 1);    //申请一个整型
double* pd = (double*)malloc(sizeof(double) * 2);   //申请两个浮点型
char* pc = (char*)malloc(sizeof(char) * 3); //申请三个字符型

注意:malloc申请的空间都是未初始化的,即被空间置为随机值。

calloc:将初始化的空间初始化为0

int* pi = (int*)calloc(1, sizeof(int)); //申请一个整型
double* pd = (double*)calloc(2, sizeof(double));    //申请两个个浮点型
char* pc = (char*)calloc(3, sizeof(char));  //申请三个字符型

注意:calloc参数列表与malloc不同,同时calloc申请的空间会被初始化为 0

realloc:对已申请的空间进行扩容

int* tmp = (int*)realloc(pi, sizeof(int) * 10); //将 pi 扩容为十个整型
pi = tmp;   //常规使用方法

注意: 我们要对所有的申请函数进行空指针检查,预防野指针问题

堆区的空间由我们管理,编译器很信任我们,因此我们要做到有借有还,再借不难

凡是动态开辟的空间,用完后都需要释放

free(tmp);  //此时tmp指向pi扩容后的空间,释放tmp就行了
tmp = pi = NULL;    //两者都需要置空
free(pd);
pd = NULL;
free(pc);   //只要是动态开辟的,都需要通过 free 释放
pc = NULL;
​

三、C++的动态管理

1、new开辟空间

void Test_CPP() {
    // 动态申请一个int类型的空间
    int* p1 = new int;
​
   // 动态申请一个int类型的空间并初始化为10
    int* p2 = new int(10);
​
    // 动态申请10个int类型的空间
    int* p3 = new int[10];
}
​
​

C++允许大括号进行初始化

int* p1 = new int[5]{1,2}         // 1 2 0 0 0
int* p2 = new int[5]{1,2,3,4,5};  // 1 2 3 4 5

2、delete释放空间

void Test_CPP() {
    int* p1 = new int;
    int* p2 = new int(10);
    int* p3 = new int[10];    // 多个对象
    
    // 单个对象,delete即可。
    delete p1;
    delete p2;
 
    // 多个对象,delete[] 。
    delete[] p3;
    
    p1 = nullptr;
    p2 = nullptr;
    p3 = nullptr;
​
}

3、new与malloc的区别与free与delete的区别

在申请自定义类型的空间时,new 会调用构造函数,

delete 会调用析构函数,而 malloc 与 free 不会。

new:在堆上申请空间 + 调用构造函数输出。

delete:先调用指针类型的析构函数 + 释放空间给堆上。

四、函数模版

函数模板代表了一个函数家族,该函数模板与类型无关,

在使用时被参数化,根据实参类型产生函数的特定类型版本。

1、函数模版格式

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}

① template 是定义模板的关键字,后面跟的是尖括号 < >

② typename 是用来定义模板参数的关键字

T1, T2, ..., Tn 表示的是函数名,可以理解为模板的名字,名字你可以自己取。

2、函数模版使用方法

来看一下这一段代码,假设要实现Add函数处理各个类型的加法。

//处理整型的加法函数
int Add(const int& a, const int& b)
{
    return a + b;
}
​
//处理浮点型的加法函数
double Add(const double& a, const double& b)
{
    return a + b;
}

这时候用一个模版既可以把他们全部搞定

template <class T> //还可以写成template <typename T>
T Add(const T& a, const T& b) {
    return a + b;
}

还可以实现多参数模版:

//定义一个多参数模版,求数的平均值
template <class T1  ,class T2>
T2 findaver( T1 arr[], int n) {
    T1 sum = 0;
    T2 aver;
    for (int i = 0; i < n;i++) {
        sum += arr[i];
    }
    aver = sum / (double)n;
    return aver;
}

总之,在函数模板的存在下,我们不再需要再编写不同类型参数的相似函数了

3、实现原理

只需要两样东西:编译器与函数重载

当我们编写好函数模板后,编译器会记住这个模板的内容,当我们使用模板时,编译器又会根据参数类型,创建相应的、具体的函数供参数使用,而这就是函数重载的道理

编译器在识别参数类型生成函数时,有两种途径:

  1. 自动识别 (隐式)

  2. 我们手动指定(显式)

3.1隐式实例化

隐式实例化就是编译器自动识别参数后生成函数的过程

//Add 模板
template <class T>
T Add(const T& a, const T& b)
{
    return a + b;
}
​
int main()
{
    Add(2, 1.5);    //此时编译失败!
    return 0;
}

解决方法一:强制类型转化

int main(){
    Add((double)2, 1.5);
    return 0;
}

3.2显式实例化

显式实例化就是给编译器打招呼,让它在建房子时按照我们的意愿来

Add<int> (2, 3.14); //此时编译器会调用 _3Addii 函数,至于传参时的类型转换,由编译器完成
Add<char> (2, 5);   //调用 _3Addcc 函数

这种行为是完全合法的,< > 符号也正式和我们见面了,在后面的 STL 学习中,< > 会经常使用到,比如生成一个类型为 int 的顺序表,直接 vector<int>,生成 char 类型的顺序表 vector<char>,一键生成,非常方便,当然还有很多容器都会用到显式实例化

五、类模版

模板除了可以用在函数上面外,还可以用在上,此时称为 类模板

STL 库中的容器,都是 类模板 的形式,我们使用时,需要什么类型的 ,直接显式实例化为对应 模板类 即可

//简单演示下 STL 中的容器,这些都是类模板的实际运用
vector<int> v1; //实例化为整型顺序表类
list<double> l1;    //实例化为浮点型链表类

类模版与函数模版不同,类模版只能显式实例化。

简单写一个类模版:

//类模版,简单写一个栈模版
//简单写一个栈模板
template<class T>
class Stack
{
public:
    //构造函数
    Stack(int capacity = 4);
​
    //析构函数
    ~Stack();
​
    //……
​
private:
    T* _pData;
    int _top;
    int _capacity;
};
​
//注意类模板中方法的实现方式!
//定义构造函数
template<class T>
Stack<T>::Stack(int capacity)
{
    _pData = new T[capacity];   //内存管理,一次申请4块空间
    _capacity = capacity;
    _top = 0;
}
​
//定义析构函数
template<class T>
Stack<T>::~Stack()
{
    delete[] _pData;    //注意:匹配使用
    _capacity = _top = 0;
}
​
int main(){
Stack<int> s1;
Stack<char> c1;
return 0;
}

类模板使用时需要注意一些问题:

  • 模板类中的函数在定义时,如果没有在类域中,就需要通过 类模板+ 类域访问 的方式定义

  • 类模板 不支持声明与定义分开在两个文件中实现,因为会出现链接错误

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

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

相关文章

( 位运算 ) 342. 4的幂 ——【Leetcode每日一题】

❓342. 4的幂 难度&#xff1a;简单 给定一个整数&#xff0c;写一个函数来判断它是否是 4 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 整数 n 是 4 的幂次方需满足&#xff1a;存在整数 x 使得 n 4 x n 4^x n4x。 示例 1&…

src学习记录(二)

学习目标&#xff1a; Apache Shiro ThinkPHP struts2 Apache Log4j Fastjson Weblogic 学习内容&#xff1a; 1.Apache Shiro 字段内容指纹信息请求包中&#xff0c;在Cookie信息中给 rememberMe变量赋任意值&#xff0c;收到返回包的Set-Cookie 值存在 rememberMedeleteMe …

类和对象【C++】【下篇】

目录 一、初始化列表 二、隐式类型转换 三、静态成员 四、友元 1、友元函数 2、友元类 五、内部类 六、匿名对象 一、初始化列表 下面是日期类的一个构造函数&#xff0c;调用该构造函数后&#xff0c;对象中已经有了一个初始值&#xff0c;但并不能将它称为对对象成员变…

实时操作系统内存管理-TLSF算法

内存管理-TLSF算法 前言TLSF算法&#xff1a;为什么内存又叫内存“块”&#xff1a;O(1)查找空闲块&#xff1a;确定fl&#xff1a;确定sl&#xff1a;提级申请&#xff1a;分割块&#xff1a; 空闲块如何串成链表&#xff1f;减少外部碎片&#xff1a;查找上下块&#xff1a; …

Java补充之MySQL入门必备知识

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/java-tutorial 】或者公众号【AIShareLab】回复 java 也可获取。 文章目录 零基础学MySQL解决之道文件、数据库MySQL 数据库的安装和配置使用命令行窗口连接MYSQL 数据库操作示意图 数据库三层结构数…

使用Intellij IDEA创建新项目时,maven路径总是默认的,一创建maven就卡死

目录 使用Intellij IDEA创建新项目时&#xff0c;maven路径总是默认的 弄了老半天&#xff0c;终于把这个破玩意给弄好了&#xff0c;真的没有意思&#xff0c;真的很恶心 我经历了两个过程&#xff0c;一个是 使用Intellij IDEA创建新项目时&#xff0c;maven路径总是默认的…

用免费蜜罐工具配置Modbus工控蜜罐

导语&#xff1a;本文将用DecoyMini免费蜜罐工具来配置自定义的ModbusTCP工控仿真模板&#xff0c;并介绍部署后的Modbus蜜罐的使用效果。 DecoyMini是一个免费的蜜罐工具&#xff0c;其特色是仿真能力采用与软件松耦合的仿真模板来进行管理。通过一键式导入云端仿真模板库里的…

【Linux】多线程 --- 线程同步与互斥+生产消费模型

人生总是那么痛苦吗&#xff1f;还是只有小时候是这样&#xff1f; —总是如此 文章目录 一、线程互斥1.多线程共享资源访问的不安全问题2.提出解决方案&#xff1a;加锁&#xff08;局部和静态锁的两种初始化/销毁方案&#xff09;2.1 对于锁的初步理解和实现2.2 局部和全局锁…

计算机中丢失msvcr120.dll怎么办,电脑找不到msvcr120.dll怎么办

电脑提示msvcr120.dll丢失是一个常见的问题&#xff0c;这个问题通常会在你尝试打开某些程序或游戏时出现。这个问题的原因是因为你的电脑缺少了一个名为msvcr120.dll的文件&#xff0c;这个文件是微软Visual C Redistrle for Visualv 2013的一部分。如果你遇到了这个问题&…

算法设计 || 第5题:田忌赛马-杭州电子科技大学(贪心算法)

目录 &#xff08;一&#xff09;杭电原题 &#xff08;二&#xff09;Please speak Chinese: &#xff08;三&#xff09;手写草稿理解思路核心算法 第一款代码&#xff1a; 第二款代码&#xff1a; &#xff08;一&#xff09;杭电原题 Tian Ji -- The Horse Racing Pro…

【分治法】

目录 知识框架No.1 分治法基本思想No.2 合并排序No.3 快速排序一、基本思想三、效率分析四、快速排序不稳定例子 No.4 二叉树遍历及其相关特性一、基本概念二、中序遍历三、前序遍历四、二叉树的高度计算(高度不是深度) 知识框架 No.1 分治法基本思想 将规模为N的问题分解为k…

Spring MVC:常用参数(注解)的使用和参数绑定的验证

Spring MVC&#xff1a;常用参数&#xff08;注解&#xff09;的使用和参数绑定的验证 一、学习资源二、基础源码三、实验结果3.1 Spring MVC常用参数Controller和RequestMappingRequestMappingRequestParamPathVariableCookie ValueRequestHeader 3.2 Spring MVC参数绑定3.2.1…

一路对标顶级产品,奇遇XR为何仍不见起色?

临近6月&#xff0c;再度遇冷的XR行业&#xff0c;又让很多人充满期待。外界普遍认为&#xff0c;基于苹果酝酿多年的MR头显产品&#xff0c;将于6月举行的WWDC 2023全球开发者大会正式亮相&#xff0c;XR行业或将迎来“iPhone时刻”。 在一派期待中&#xff0c;一家国内XR企业…

代码审计之PHP基础铺垫

目录 1、标记 2、注释 3、输出语句 4、关键字 5、常量的定义与使用 6、预定义常量 7、变量的赋值&#xff08;传参赋值与引用赋值&#xff09; 8、可变变量 9、双引号和单引号的区别 10、heredoc结构和nowdoc结构 11、其他符号 1、标记 <?php 和 ?> 是PHP标…

第十一届蓝桥杯青少组省赛Python中/高级组编程题真题,包含答案解析

第十一届蓝桥杯青少组省赛Python中/高级组编程题真题 编程实现 第一题&#xff1a; 输入一个字符串&#xff0c;如果该字符串以er、Iy或者ing后缀结尾的&#xff0c;则删除该字符串后缀&#xff0c;并输出删除后的字符串&#xff0c;否者将原字符串输出。 输入描述 输入一个…

零知识证明:应用和具体用例

零知识证明&#xff08;Zero-Knowledge Proofs&#xff0c;ZKPs&#xff09;是应用密码学中令人兴奋的突破&#xff0c;将在各个行业中解锁新的用例&#xff0c;从 Web3 到供应链再到物联网。通过在不揭示信息的情况下验证其真实性&#xff0c;ZKPs 可以增强数字系统的隐私、安…

【Unity-UGUI控件全面解析】| Slider 滑动条组件详解

🎬【Unity-UGUI控件全面解析】| Slider 滑动条组件详解一、组件介绍二、组件属性面板三、代码操作组件四、组件常用方法示例4.1 充当 进度条控制灯光亮度4.2 模拟 血条 使用💯总结🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CS…

【Spring全家桶系列】面向切面编程AOP

⭐️前面的话⭐️ 本文已经收录到《Spring框架全家桶系列》专栏&#xff0c;本文将介绍面向切面编程的思想和相关概念&#xff0c;附加一个小案例。 &#x1f4d2;博客主页&#xff1a;未见花闻的博客主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&a…

基于Kubernetes集群构建大中型企业CICD应用平台(2)--code阶段工具gitlab安装

这里我们为gitlab服务器准备一台虚拟机&#xff1a;192.168.19.6-gitlab服务器 在code阶段&#xff0c;我们需要将不同版本的代码存储到一个仓库中&#xff0c;常见的版本控制工具就是SVN或者Git&#xff0c;这里我们采用Git作为版本控制工具&#xff0c;GitLab作为远程仓库。…

django常用命令/vue-cli图形化界面创建方式/vueo-cli命令行创建方式/若依框架/elementui

django常用命令 django-admin.exe startproject mysite python .\manage.py startapp app01 python manage.py makemigrations python manage.py migrate python manage.py runserver python manage.py runserver 0.0.0.0:8000 from django.shortcuts import render,Http…