c++的学习之路:8、内存管理与模板

一、 C/C++内存分布

首先在c语言的动态内存管理中我知道了代码是如何存储数据的,然后c++是根据c语言底层变化来的,那么c语言的内存管理就是适用c++的内存管理,在c语言中程序是分为几个部分存储,例如在栈堆等等,他们的分布如下图就是一个分布,有点抽象。

1、栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。

2、 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)

3、堆用于程序运行时动态内存分配,堆是可以上增长的。

4、数据段--存储全局数据和静态数据。

5、代码段--可执行的代码/只读常量。

二、C语言中动态内存管理方式

c语言的内存管理就是利用malloc/calloc/realloc/free,如下方代码所示就是利用这几个函数去管理的,这里就不细说了,在C语言内存管理说的比较详细,这里可以看出malloc申请的空间,realloc是扩容,但是都不进行初始化,这个calloc会初始化,所以可以看出下方图片test2是0。

int main()
{
    int* testptr1 = (int*)malloc(sizeof(int));
    if (testptr1 == nullptr)
    {
        perror("malloc fail");
        return NULL;
    }
    int* testptr2 = (int*)calloc(4, sizeof(int));
    if (testptr2 == nullptr)
    {
        perror("calloc fail");
        return NULL;
    }
    int* testptr3 = (int*)realloc(testptr1, sizeof(int) * 10);
    if (testptr3 == nullptr)
    {
        perror("realloc fail");
        return NULL;
    }
    //free(testptr1);
    free(testptr2);
    free(testptr3);
    return 0;

三、 C++中动态内存管理

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因
此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。如下图代码就是利用new去开辟空间,可以看到代码中,ptr1就是开辟了一个int的空间,ptr2就是开辟了一个int然后并且初始化,delect就是相当于free,注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与
free不会。

void Test()
{
    int* ptr1 = new int;
    int* ptr2 = new int(10);
    int* ptr3 = new int[3];
    delete ptr1;
    delete ptr2;
    delete[] ptr3;
}

四、 operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator  new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。怎么说呢这两个函数其实就是起的函数名叫这个,并不是函数重载这里要分清楚,从下方代码可以看出。

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空               间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)

    if (_callnewh(size) == 0)
    {
        // report no memory
        // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
        static const std::bad_alloc nomem;
        _RAISE(nomem);
    }
return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
    _CrtMemBlockHeader * pHead;
    RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
    if (pUserData == NULL)
        return;
    _mlock(_HEAP_LOCK);  /* block other threads */
    __TRY
        /* get a pointer to memory block header */
        pHead = pHdr(pUserData);
         /* verify block type */
        _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
        _free_dbg( pUserData, pHead->nBlockUse );
    __FINALLY
        _munlock(_HEAP_LOCK);  /* release other threads */
    __END_TRY_FINALLY
    return;
}

五、new和delete的实现原理

1、内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申
请空间失败时会抛异常,malloc会返回NULL。

2、自定义类型new的原理

① 调用operator new函数申请空间

②在申请的空间上执行构造函数,完成对象的构造

delete的原理

① 在空间上执行析构函数,完成对象中资源的清理工作

② 调用operator delete函数释放对象的空间

new T[N]的原理

①调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请

②在申请的空间上执行N次构造函数

delete[]的原理

① 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理

② 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

六、泛型编程

像下方代码这样交换需要使用很多次的时候,每次都要写个对应的交换就会显得很麻烦,如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

void Swap(int& a1, int& a2)
{
    int tmp = a1;
    a1 = a2;
    a2 = tmp;
}

void Swap(double& a1, double& a2)
{
    double tmp = a1;
    a1 = a2;
    a2 = tmp;
}

int main()
{
    int a1 = 10, a2 = 20;
    double b1 = 11.11, b2 = 22.22;
    Swap(a1, a2);
    Swap(b1, b2);
    return 0;
}

七、函数模板

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

他的格式如下,编写的测试代码如下,这里也是可以class

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

 template<typename T>
void Swap(T& a1, T& a2)
{
    T temp = a1;
    a1 = a2;
    a2 = temp;
}

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

1. 隐式实例化:让编译器根据实参推演模板参数的实际类型 

2. 显式实例化:在函数名后的<>中指定模板参数的实际类型

如同下方代码就是利用显式实例化,因为两个不同的类型就没有找到对应的实例化,所以这里就是用了显式实例化,结果如图。

template<typename T>
T Add(const T& a1, const T& a2)
{
    return a1 + a2;
}

int main()
{
    int a1 = 10, a2 = 20;
    double b1 = 11.11, b2 = 22.22;
    cout << Add(a1, a2) << endl;
    cout << Add(b1, b2) << endl;
    cout << Add<int>(a1, b2) << endl;
    cout << Add<double>(b1, a2) << endl;
    return 0;
}

其次就是一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数,对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板,模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。

八、类模板

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

类模版格式代码如下

template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
public :
Vector(size_t capacity = 10)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
// 使用析构函数演示:在类中声明,在类外定义。
~Vector();
void PushBack(const T& data);
void PopBack();
// ...
size_t Size() {return _size;}
T& operator[](size_t pos)
{
assert(pos < _size);
return _pData[pos];
}
private:
T* _pData;
size_t _size;
size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
if(_pData)
delete[] _pData;
_size = _capacity = 0;
}

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

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

相关文章

Golang并发模型-Pipeline模型、Fan-in Fan-out模型

这段时间由于项目的需要&#xff0c;本人正在研究关于如何优雅的进行go的并发&#xff0c;以下是结合资料和视频的结果&#xff0c;文末会给出参考资料 Go语言的并发模型主要通过goroutine和channel实现&#xff0c;通过这个我们可以更有效地使用IO和CPU 这里我们围绕生成一个…

【随笔】Git 基础篇 -- 分支与合并(九)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

mysql 基本查询

学习了mysql函数&#xff0c;接下来学习mysql基本查询。 1&#xff0c;基本查询语句 MySQL从数据表中查询数据的基本语句为SELECT 语句。SELECT语句的基本格式是&#xff1a; SELECT (*I <字段列表>} FROM <表1>,<表2>..[WHERE<表达式> [GROUP BY <…

手写简易操作系统(二十一)--硬盘驱动

前情提要 上面一节我们实现了 malloc 和 free 的系统调用&#xff0c;这一节我们来实现硬盘驱动。 一、硬盘分区 我们的文件系统安装在一块全新的硬盘中&#xff0c;我们先创建它&#xff0c;然后在给他分区。 1.1、创建硬盘 首先是创建&#xff0c;这个之前我们已经干过一…

Linux网络编程一(协议、TCP协议、UDP、socket编程、TCP服务器端及客户端)

文章目录 协议1、分层模型结构2、网络应用程序设计模式3、ARP协议4、IP协议5、UDP协议6、TCP协议 Socket编程1、网络套接字(socket)2、网络字节序3、IP地址转换4、一系列函数5、TCP通信流程分析 第二次更新&#xff0c;自己再重新梳理一遍… 协议 协议&#xff1a;指一组规则&…

Kafka架构概述

Kafka的体系结构 Kafka是由Apache软件基金会管理的一个开源的分布式数据流处理平台。Kafka具有支持消息的发布/订阅模式、高吞吐量与低延迟、持久化、支持水平扩展、高可用性等特点。可以将Kafka应用于大数据实时处理、高性能数据管道、流分析、数据集成和关键任务应用等场景。…

20240402—Qt如何通过动态属性设置按钮样式?

前言 正文 1、点击UI文件 2、选择Bool型或是QString 3、设置后这里出现动态属性 4、这qss文件中绑定该动态属性 QPushButton[PopBlueBtn"PopBlueBtn"]{background-color:#1050B7;color:#FFFFFF;font-size:20px;font-family:Source Han Sans CN;//思源黑体 CNbor…

【JavaEE初阶系列】——一万字带你了解 JUC常见类 以及 线程安全集合类(哈希表)

目录 &#x1f6a9;JUC(java.util.concurrent) 的常见类 &#x1f388;Callable 接口 &#x1f308;理解 Callable(相关面试题) &#x1f308;理解 FutureTask &#x1f4dd;线程创建方式 &#x1f388; ReentrantLock可重入锁 &#x1f308;ReentrantLock 优势&#x…

4.2日java总结,以及窗口的创建

今日份学习——字符串的进阶 1.StringBulider StringBulider是一个java里的关键字&#xff0c;可以看做一个容器&#xff0c;但是其是一个可以改变的容器&#xff0c;对其有四种操作可以进行&#xff0c;分别是添加元素&#xff08;append&#xff09;&#xff0c;反转元素&a…

谷粒商城实战(009 缓存-分布式锁)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第158p-第p165的内容 分布式锁 原理和使用 使用下shell对产生的命令进行发送 查看 -> 撰写 -> 撰写栏 idea 选中的代码提取成方法 加锁…

【教学类-09-07】20240401细线迷宫图02+箭头图片(A4横版一页-2份竖版)

作品展示 作品展示 word模板 重点说明 代码展示 批量制作细线条的迷宫图(A4横板一面2张竖版)箭头图片 作者&#xff1a; 1、落难Coder https://blog.csdn.net/u014297502/article/details/124839912 2、AI对话大师 3、阿夏 作者&#xff1a;2024年4月3日 numint(input(几人&…

Android14之BpBinder构造函数Handle拆解(二百零四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Docker:探索容器化技术,重塑云计算时代应用交付与管理

一&#xff0c;引言 在云计算时代&#xff0c;随着开发者逐步将应用迁移至云端以减轻硬件管理负担&#xff0c;软件配置与环境一致性问题日益凸显。Docker的横空出世&#xff0c;恰好为软件开发者带来了全新的解决方案&#xff0c;它革新了软件的打包、分发和管理方式&#xff…

AIGC之gradio系列学习教程(一)

主题:本篇即为入门,后续将会从函数和使用场景介绍。 Gradio 是一个开源 Python 包,可让快速为机器学习模型、API 或任何任意 Python 函数构建演示或 Web 应用程序。然后,您可以使用 Gradio 的内置共享功能在短短几秒钟内共享演示或 Web 应用程序的链接。无需 JavaScript、…

C#中值类型与引用类型的存储

目录 值对象与引用对象的存储 引用对象的成员存储 值对象与引用对象的存储 数据项的类型定义了存储数据需要的内存大小及组成该类型的数据成员。类型还决定了对象在内存中的存储位置——栈或堆。 C#中类型分为两种&#xff1a;值类型和引用类型&#xff0c;这两种类型的对象…

【蓝桥杯 C++高级组省赛以及2020年-蓝桥杯C++省赛合集+部分答案】

一、选择题&#xff08;单项选择&#xff0c;每空30分&#xff09; 请将选择题答案填入答题卡蓝色框内 第一题&#xff08;难度系数 1&#xff09; 结构化程序所要求的基本结构不包括( )。 A.顺序结构 B.GOTO()跳转 C.选择(分支)结构 D.重复(循环)结构 第二题&#xff…

银行监管报送系统介绍(十五):金融审计平台

《“十四五”国家审计工作发展规划》中重点强调&#xff0c;金融审计&#xff1a;以防范化解重大风险、促进金融服务实体经济&#xff0c;推动深化金融供给侧结构性改革、建立安全高效的现代金融体系为目标&#xff0c;加强对金融监管部门、金融机构和金融市场运行的审计。 —…

面试题:MySQL 事务 日志 MVCC

事务的特性 ACID 事务的隔离级别 并发事务问题 脏读&#xff1a;一个事务读到另一个事务还没有提交的数据不可重复读&#xff1a;一个事务先后读取同一条记录&#xff0c;但两次读取的数据不同幻读&#xff1a;一个事务按照条件查询数据时&#xff0c;没有对应的数据行&#xf…

Oracle EBS AR接口和OM销售订单单价为空数据修复

最近,用户使用客制化Web ADI 批量导入销售订单行功能,把销售订单行的单价更新成空值,直到发运确认以后,财务与客户对帐才发现大量销售订单的单价空,同时我们检查AR接口发现销售订单的单价和金额均为空。 前提条件 采用PAC成本方式具体问题症状 销售订单行的单价为空 Path:…

Redhat 7.9 安装dm8配置文档

Redhat 7.9 安装dm8配置文档 一 创建用户 groupadd -g 12349 dinstall useradd -u 12345 -g dinstall -m -d /home/dmdba -s /bin/bash dmdba passwd dmdba二 创建目录 mkdir /dm8 chown -R dmdba:dinstall /dm8三 配置/etc/security/limits.conf dmdba soft nproc 163…