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

news2024/10/6 4:05:20

一、 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.coloradmin.cn/o/1575272.html

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

相关文章

解决 macOS 系统向日葵远程控制鼠标、键盘无法点击的问题

解决 macOS 系统向日葵远程控制鼠标\键盘无法点击的问题 1、首先正常配置&#xff0c;在系统偏好设置 - 安全性与隐私内&#xff0c;将屏幕录制、文件和文件夹、完全的磁盘访问权限、辅助功能全部都加入向日葵客户端 2、通过打开的文件访达&#xff0c;使用command shift G…

c++ Constraints 和 concepts介绍

C++20 引入了 Concepts,以改进模板编程的体验。Concepts 是一种用于模板编程的新机制,它允许程序员在编译时对模板参数进行约束和限制,从而提高模板的可读性、可维护性和错误检测能力。 Constraints(约束)是 Concepts 的一部分,它定义了模板参数必须满足的条件。一个约束…

入门微调预训练Transformer模型

大家好&#xff0c;HuggingFace 为众多开源的自然语言处理&#xff08;NLP&#xff09;模型提供了强大的支持平台&#xff0c;让这些模型能够通过训练和微调来更好地服务于各种特定的应用场景。在大型语言模型&#xff08;LLM&#xff09;迅猛发展的今天&#xff0c;HuggingFac…

100 个网络基础知识,看完成半个网络高手

100 个网络基础知识&#xff0c;看完成半个网络高手。 1)什么是链接? 链接是指两个设备之间的连接。它包括用于一个设备能够与另一个设备通信的电缆类型和协议。 2)OSI 参考模型的层次是什么? 有 7 个 OSI 层&#xff1a;物理层&#xff0c;数据链路层&#xff0c;网络层&…

Rustdesk二次编译,新集成AI功能开源Gpt小程序为远程协助助力,全网首发

环境&#xff1a; Rustdesk1.1.9 sciter版 问题描述&#xff1a; Rustdesk二次编译&#xff0c;新集成AI功能开源Gpt小程序为远程协助助力,全网首发 解决方案&#xff1a; Rustdesk二次编译&#xff0c;新集成开源AI功能Gpt小程序&#xff0c;为远程协助助力&#xff0c…

何为HTTP状态码?一文清楚基本概念。

在客户端与服务器之间的信息传输过程中&#xff0c;我们可以将其比喻为客户与快递员之间的包裹传递。那么服务器是如何通知客户端&#xff0c;操作是成功还是失败&#xff1f;或者有其他的一些情况呢&#xff1f;&#xff08;就像客户可以查询快递的状态&#xff09; 而这背后…

C++分析程序各模块耗时-perf火焰图

C分析程序各模块耗时-perf火焰图 1. 简介2. 安装3. 测试示例4. 从火焰图可以获得的信息5. 生成火焰图常见问题 Reference: Perf Wiki【性能】perf 火焰图分析软件性能瓶颈【火焰图&#x1f525;】Linux C/C性能优化分析工具Perf使用教程 perf: Linux profiling with perform…

【Python】还在用print进行调试,你Out了!!!

1. 引言 Python 中最常用的函数是什么&#xff1f;像在大多数编程语言中&#xff0c;print() 函数是最常用的。我相信大多数开发者都会像我一样&#xff0c;在开发过程中多次使用它将信息进行打印。 当然&#xff0c;没有其他方法可以完全取代print()函数。不过&#xff0c;当…

鱼塘钓鱼(c++实现)

题目 有 N 个鱼塘排成一排&#xff0c;每个鱼塘中有一定数量的鱼&#xff0c;例如&#xff1a;N5 时&#xff0c;如下表&#xff1a; 即&#xff1a;在第 1 个鱼塘中钓鱼第 1 分钟内可钓到 10 条鱼&#xff0c;第 2 分钟内只能钓到 8 条鱼&#xff0c;……&#xff0c;第 5 分…

【JavaEE】_Spring MVC项目获取Cookie

目录 1. Cookie与Session基础知识 1.1 Cookie与Session的区别 2. 使用servlet原生方法获取Cookie 2.2 关于λ表达式遍历法的空指针问题 2.3 Cookie的伪造 3. 使用Spring注解获取Cookie 3.1 获取单个Cookie 3.2 获取多个Cookie 1. Cookie与Session基础知识 在本专栏HTT…

【随笔】Git 高级篇 -- 整理提交记录(上)cherry-pick(十五)

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

docker-compose安装adguard给局域网提供dns加速服务

启动配置 docker-compose.yaml配置文件 version: 3.3 services:adguard:image: adguard/adguardhome:latestcontainer_name: adguardrestart: unless-stoppedvolumes:- ./workdir:/opt/adguardhome/work- ./confdir:/opt/adguardhome/confports:- 53:53/tcp- 53:53/udp- 81:8…

【fdisk 相关分区命令记录】

目的 记录下新磁盘下刚刚分配的系统&#xff08;安装系统后未操作或者新扩容的)的分区格式化及挂载&#xff0c;比如这里运维分配了100G 步骤&#xff1a; 1.查看新硬盘 lsblk -f查看&#xff0c;sdb就是新分配的硬盘&#xff0c;无任何相关的属性信息 2、分区明细查看 fd…

鸿蒙内核源码分析 (双向链表篇) | 谁是内核最重要结构体

双向链表是什么&#xff1f; 谁是鸿蒙内核最重要的结构体 &#xff1f; 一定是: LOS_DL_LIST(双向链表)&#xff0c; 它长这样。 typedef struct LOS_DL_LIST {struct LOS_DL_LIST *pstPrev; /**< Current nodes pointer to the previous node | 前驱节点(左手)*/struct L…

ZYNQ学习Linux 基础外设的使用

基本都是摘抄正点原子的文章&#xff1a;《领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf》&#xff0c;因初次学习&#xff0c;仅作学习摘录之用&#xff0c;有不懂之处后续会继续更新~ 工程的创建参考&#xff1a;《ZYNQ学习之Petalinux 设计流程实战》 一、GPIO 之 LED 的使…

Open CASCADE学习|旋转变换

物体在三维空间中的旋转变换操作通常可以通过三种不同的方式来表示&#xff1a;矩阵&#xff08;Matrix&#xff09;、欧拉角&#xff08;Euler Angles&#xff09;和四元数&#xff08;Quaternion&#xff09;。下面详细解释这三种表示方法。 矩阵&#xff08;Matrix&#xf…

SpringCloud学习(10)-SpringCloudAlibaba-Nacos服务注册、配置中心

Spring Cloud Alibaba 参考文档 Spring Cloud Alibaba 参考文档 nacos下载Nacos 快速开始 直接进入bin包 运行cmd命令&#xff1a;startup.cmd -m standalone 运行成功后通过http://localhost:8848/nacos进入nacos可视化页面&#xff0c;账号密码默认都是nacos Nacos服务注…

全景化工厂虚拟场景VR在线编辑突破传统束缚

数字化时代来临&#xff0c;让很多行业发生了天翻地覆的变化&#xff0c;更多人和企业接纳和亲近VR/AI/3D等技术&#xff0c;虚拟仿真VR内容编辑器系统不仅在畜牧培训领域大放异彩&#xff0c;更在其他多个行业领域展现出广泛的应用前景。 相比传统的VR虚拟现实应用程序开发依赖…

如何使用开源情报跟踪一个人?在线访问网站以及使用方法介绍

如何使用开源情报跟踪一个人&#xff1f;在线访问网站以及使用方法介绍。 开源情报&#xff08;OSINT&#xff09;是一门关于收集和分析公开可用信息的独特技艺&#xff0c;它致力于构建个人或团体的详尽档案。 这一过程中&#xff0c;信息搜集者会利用多元化的信息源&#xff…

如何使用 langchain 与 openAI 连接

上一篇写了如何安装 langchain https://www.cnblogs.com/hailexuexi/p/18087602 这里主要说一个 langchain的使用 创建一个目录 langchain &#xff0c;在这个目录下创建两个文件 main.py 这段python代码&#xff0c;用到了openAI&#xff0c;需要openAI及FQ。这里只做…