C++学习笔记----6、内存管理(一)---- 使用动态内存(3)

3.2、对象数组

        对象数组与原型/基础类型的数组没有什么不同,除了元素的初始化之外。当你使用new[N]去分配N个对象,就把N个连续的块空间分配出去了,每一个块空间可以放一个单独的对象。对于对象数组,New[]对每一个对象自动调用0参数(也就是缺省)构造函数,而原型数组清爽型缺省是没有被初始化的元素。用这种方式,使用new[]来分配对象数组返回一个指向完全构造并且初始化了的对象的指针。

       例如,考虑以下的类:

class Simple
{
public:Simple() { println("Simple constructor called!"); }˜Simple() { println("Simple destructor called!"); }
};

       如果你分配了四个Simple对象的数组,Simple的构造函数就被调用了四次。

Simple* mySimpleArray { new Simple[4] };

        下图展示了数组的内存图示。可以看到,与基本类型的数组没有什么区别。

3.3、删除数组

       当你用new[](也就是new的数组版本)来分配内存时,也要用delete[](也就是delete的数组版本)来释放它。这个版本自动析构数组中的对象并且释放与其关联的内存。

Simple* mySimpleArray { new Simple[4] };
// Use mySimpleArray...
delete [] mySimpleArray;
mySimpleArray = nullptr;

       如果你不使用数组版本的delete,你的程序运行可能就会很怪异。对于有些编译器,只有数组的第一个元素的析构函数会被调用,因为编译器只知道你在删除一个指向对象的指针,数组的其他元素就会变成孤儿对象。而对于其他的编译器,内存可能会出现崩溃,因为new与new[]用的内存分配模式完全不一样。

       对于用new分配的要用delete,而对于用new[]分配的要用delete[]。

       当然了,只有数组的元素为对象时才需要调用析构函数。如果你有一个指针数组,你仍然需要删除为每个对象单独分配的空间。如下代码所示:

const size_t size { 4 };
Simple** mySimplePtrArray { new Simple*[size] };
// Allocate an object for each pointer.
for (size_t i { 0 }; i < size; ++i) { mySimplePtrArray[i] = new Simple{}; 
}
// Use mySimplePtrArray...
// Delete each allocated object.
for (size_t i { 0 }; i < size; ++i) {delete mySimplePtrArray[i];mySimplePtrArray[i] = nullptr;
}
// Delete the array itself.
delete [] mySimplePtrArray;
mySimplePtrArray = nullptr;

        在现代C++中,当有属主介入时,应该避免使用原始C风格的指针。不要把原始指针存储在C风格的数组中,应该把智能指针存储在现代标准构造函数中,比如std::vector。我们马上要讨论的智能指针会自动地在合适的时间将与其关联的内存释放掉。

3.4、多维数组

        多维数组将索引值的记号扩展到多个索引。例如,一个跳跳棋游戏可能会使用一个二维的数组来代表一个3乘3的网格。下面的例子展示了在栈上声明的一个数组,用0进行了初始化,以及一些测试代码:

char board[3][3] {};
// Test code
board[0][0] = 'X'; // X puts marker in position (0,0).
board[2][1] = 'O'; // O puts marker in position (2,1).

        你可能会想二维数组的第一个下标是X坐标还是Y坐标呢。事实是它并不重要,只要保持一致就行。一个4乘7的网格可以声明为char board[4][7]或者board[7][4]。对于大部分应用来说,第一个下标为x轴第二个下标为y轴可能更容易理解。

3.5、多维栈数组

        在内存中,3乘3的栈的二维board数组看起来像下图。

       因为内存不是二维的(地址是连续的),计算机标识二维数组也会像一维数组一样。不同之处在于数组的大小有及用什么方法来访问。

       多维数组的大小是所有维度相乘,然后乘以数组中的单个元素的大小。在上图中,3乘3的游戏板就是3*3*1=9个字节,假设一个字符是一个字节。对于一个4乘4的字节游戏板来说,数组就是4*7*1=28个字节。

       要访问多维数组中的一个值,计算机将每一个下标视为多维数组中的一个子数组。例如,3乘3的网格,board[0]实际上就是下图中高亮的子数组。

       当你加上第二个下标,比如board[0][2],计算机就会通过子数组中的第二个下标查找到正确的元素进行访问,如下图所示:

        这个技巧可以扩展到N维数组,虽然高于三维的数组难于概念化并且较少被用到。

3.6、多维自由内存空间上的数组

       如果需要在运行时决定多维数组的维度,可以使用在自由内存空间上的数组。与一维动态分配的数组通过指针访问一样,多维动态分配的数组也可以通过指针访问。不同的地方在于在二维数组中,需要用一个指向指针的指针;在一个N维的数组中,需要N层的指针。一开始,好像正确的方式是声明并且分配一个动态分配的多维数组如下:

char** board { new char[i][j] }; // BUG! Doesn't compile

        该代码编译不通过,因为多维自由内存空间上的数组与栈上数组不一样。其内存构成不是连续的。实际情况是,是在自由内存空间上为第一个下标维度用分配一个连续的数组开始。数组的每一个元素实际上是指向另一个保存了第二个下标维度的元素的数组的指针。下图展示了2乘2动态分配游戏板的构成。

        不幸的是,编译器不会为你对子数组进行内存分配。你可以像一维自由内存空间上的数组那样分配第一维的数组。但是每一个子数组必须显示分配。下面的函数正确地为一个二维数组分配了内存:

char** allocateCharacterBoard(size_t xDimension, size_t yDimension)
{char** myArray { new char*[xDimension] }; // Allocate first dimensionfor (size_t i { 0 }; i < xDimension; ++i) {myArray[i] = new char[yDimension]; // Allocate ith subarray}return myArray;
}

        同样的,当你想要对自由内存空间上的多维数组进行内存释放时,delete[]语法也不能为你清理子数组。释放数组的代码与分配的代码相对应,如下函数:

void releaseCharacterBoard(char**& myArray, size_t xDimension)
{for (size_t i { 0 }; i < xDimension; ++i) {delete [] myArray[i]; // Delete ith subarraymyArray[i] = nullptr;}delete [] myArray; // Delete first dimensionmyArray = nullptr;
}

       上面的为多维数组分配内存的例子并不是一个非常高效的解决方案。它首先为第一维分配了内存,接着为每一个子数组分配了内存。结果就是内存块在内存中散落各处,对于这样的数据结构上的算法来讲有很大的性能影响。如果算法在连续的内存上会跑得更快。好的解决方案是分配一个单独的内存块,足够保存xDimension * yDimension个元素,用像x*yDimension + y的公式来访问(x,y)位置的元素。

       既然你已经知道了数组工作的细节,推荐你尽可能避免这些旧的C风格的数组,因为它们不能提供内存安全。在这儿解释这么多,是因为你会在遗留的代码中会碰到。在新的代码中,应该使用C++标准库函数,比如std::array与vector。例如,使用vector<T>来用一维动态数组。对于二维动态数组 ,可以使用vector<vector<T>>,再多维的数组也类似。当然了,直接使用像vector<vector<T>>这样的数据结构也比较烦,特别是要构造它们,也会有前面讨论的同样的内存碎片问题。所以啊,如果在你的应用中确实需要N维动态数组,考虑写一个helper类,提供一个易于使用的接口。例如,对于二维数据,有同样长的行,你可以考虑写(当然也可以重用)一个Matrix<T>或者Table<T>类模板,把内存分配/释放与用户访问元素算法隐藏下来,我们以后会专门讨论写类模板的细节。

       不要使用C风格的数组,要使用C++标准库函数,比如std::array,vector等等。

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

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

相关文章

激光雷达产品介绍

与传统激光雷达线性重复式的扫描方式不同&#xff0c;Livox mid系列激光雷达扫描路径不会重复。且视场中激光照射到的区域面积会随时间增大&#xff0c;这就意味着视场覆盖率随时间推移而显著提高。 内容参考自《解构大疆旗下 Livox Mid 激光雷达非重复扫描技术》作者&#xff…

【C++11(一)之入门基础)】

文章目录 C简介统一的列表初始化&#xff5b;&#xff5d;初始化 std::initializer_liststd::initializer_list是什么类型&#xff1a;std::initializer_list使用场景&#xff1a; 声明autodecltypenullptr STL中一些变化 C简介 在2003年C标准委员会曾经提交了一份技术勘误表(…

#ARM开发 笔记

课程介绍 ARM开发 --> Linux移植 --> 驱动开发 前后联系&#xff1a;ARM和系统移植为驱动开发学习做准备工作 所需知识&#xff1a;C语言基础及STM32需要的硬件知识 学习方法 学习流程、思想和解决问题的方法即可 知道驱动的基本框架以及基本开发要求 底层课程导学 接口技…

linux小程序-进度条

文章目录 pro.hpro.cmain.cmakefile测试 pro.h #pragma once#include <stdio.h>typedef void(*callback_t)(double, double);void probar(double total, double current);pro.c #include "pro.h" #include <string.h> #include <unistd.h> #defi…

webshell绕过样本初体验

目录 一&#xff1a;前景 二&#xff1a;样本 样本一&#xff1a; 样本二&#xff1a; 样本三&#xff1a; 样本4&#xff1a; 样本5&#xff1a; 一&#xff1a;前景 在我们日常的网站中百分之一百是存在一些安全设备来拦截我们的webshell的&#xff0c;一般情况…

Kafka大厂面试14问(附答案)

怎么保证顺序消费&#xff1f; 同一个生产者发送到同一分区的消息&#xff0c;先发送的比后发送的offset要小。同一生产者发送到不同分区的消息&#xff0c;消息顺序无法保证。 怎么解决这个问题&#xff1f; 给一个topic只设置一个分区 相同key会发给一个分区 怎么保证幂…

[有彩蛋]大模型独角兽阶跃星辰文生图模型Step-1X上线,效果具说很炸裂?快来看一手实测!

先简单介绍一下阶跃星辰吧 公司的创始人兼CEO是姜大昕博士&#xff0c;他在微软担任过全球副总裁&#xff0c;同时也是微软亚洲互联网工程研究院的副院长和首席科学家。 2024年3月&#xff0c;阶跃星辰发布了Step-2万亿参数MoE语言大模型预览版&#xff0c;这是国内初创公司首…

Centos7通过reposync搭建本地Yum源

目录 1. 服务端搭建 1.1. 安装相关软件包 1.2. 加载几个常用的yum源 1.3. 创建文件保存目录 1.4. 把各仓库同步到本地 1.5. 生成仓库信息 1.6. 定时任务更新仓库 1.7. nginx配置下载服务 1.8. 内网测试nginx服务配置是否正确 2. 客户端配置 前言&#xff1a;之前使用…

Nginx负载均衡数据流分析

1、各机器ip信息 客户端IP&#xff1a;192.168.3.239 Nginx代理服务器IP&#xff1a;192.168.3.241 服务端IP&#xff1a;192.168.3.238 2、架构图&#xff08;略&#xff09; 3、 下图是在服务端上面的抓包分析。 下图是在客户端上面的抓包分析&#xff1a; 下图是在代理服务…

动态路由和路由导航守卫及其案例分析

为什么需要动态路由&#xff1f; 动态路由其实用的不多&#xff0c;在实际开发中&#xff0c;如果遇到权限分配问题&#xff0c;比如对于一个公司人员的后台管理系统&#xff0c;那对不同成员的权限肯定不同&#xff0c;对于人事部&#xff0c;他们有权限进入成员表对人员的流…

PHP8、ThinkPHP8框架中间的应用教程详解

前言 虽然PHP的落幕的话题一直不绝&#xff0c;但是实际在WEB端项目中PHP占有率达到了70%以上&#xff0c;一直在WEB一枝独秀&#xff0c;它以快速、高效的开发闻名&#xff0c;出圈了几十年&#xff0c;等待只是下一次的涅槃。而经过PHP8、PHP9的演变发展&#xff0c;PHP逐渐…

【Linux网络编程】协议|OSI模型|TCP/IP模型|局域网通信|跨网络通信|地址管理|流程图

目录 ​编辑 一&#xff0c;协议 协议分层 二&#xff0c;OSI七层模型 三&#xff0c;TCP/IP五层&#xff08;或四层&#xff09;模型 TCP/IP各个层次一些名词解释 为什么要有TCP/IP协议 TCP/IP协议栈与操作系统的宏观关系示意图 四&#xff0c;网络传输基本流程 局…

【书生大模型实战营】MindSearch CPU-only 版部署

MindSearch CPU-only 版部署 MindSearch CPU-only 版部署任务步骤 MindSearch CPU-only 版部署 任务 将 MindSearch 部署到 HuggingFace 并美化 Gradio 的界面&#xff0c;并提供截图和 Hugging Face 的Space的链接。 步骤 按照官方教程&#xff0c;实现在网页上打开MindSe…

llama_factory Qlora微调异常 No package metadata was found for The ‘autoawq‘

importlib.metadata.PackageNotFoundError: No package metadata was found for The ‘autoawq’ distribution was not found and is required by this application. To fix: pip install autoawq 其实问题比较简单 直接安装autoawq 即可 但是对应会有版本问题&#xff1a; 查…

Python自适应光学模态星形小波分析和像差算法

&#x1f3af;要点 &#x1f3af;星形小波分析像差测量 | &#x1f3af;对比傅里叶和小波分析 | &#x1f3af;定义多尺度图像质量度量&#xff0c;矩阵数据 | &#x1f3af;像差校正算法 | &#x1f3af;受激发射损耗显微镜布局 | &#x1f3af;干涉仪分支校准&#xff0c;求…

【unity实战】使用新版输入系统Input System+Rigidbody实现第三人称人物控制器(附项目源码)

最终效果 前言 使用CharacterController实现3d角色控制器&#xff0c;之前已经做过很多了&#xff1a; 【unity小技巧】unity最完美的CharacterController 3d角色控制器&#xff0c;实现移动、跳跃、下蹲、奔跑、上下坡、物理碰撞效果&#xff0c;复制粘贴即用 【unity实战】C…

快速入门Go:Go + gin + MongoDB

Go 进阶:Go + gin + MongDB 极速搭建EcommerceSys电商系统 前言 本章节适合有一定基础的 Golang 初学者,通过简单的项目实践来加深对 Golang 的基本语法和 Web 开发的理解。 本文章持续更新中,请关注… 项目结构 项目流程图 技术栈(待补充)项目结构项目路由 (待补充) …

DataWhale AI夏令营-《李宏毅深度学习教程》笔记-task3

DataWhale AI夏令营-《李宏毅深度学习教程》笔记-task2 第五章 循环神经网络5.1 独热编码5.2 RNN架构5.3 其他RNN5.3.1 Elman 网络 &Jordan 网络5.3.2 双向循环神经网络 第五章 循环神经网络 循环神经网络RNN&#xff0c;RNN在处理序列数据和时间依赖性强的问题上具有独特…

51单片机——实时时钟

1、DS1302介绍 DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时&#xff0c;且具有闰年补偿等多种功能 RTC(Real Time Clock)&#xff1a;实时时钟&#xff0c;是一种集成电路&#xff0c;通常称为时钟…

机器学习项目——基于机器学习(RNN LSTM 高斯拟合 MLP)的锂离子电池剩余寿命预测方法研究(代码/论文)

完整的论文代码见文章末尾 以下为核心内容和部分结果 摘要 机器学习方法在电池寿命预测中的应用主要包括监督学习、无监督学习和强化学习等。监督学习方法通过构建回归模型或分类模型&#xff0c;直接预测电池的剩余寿命或健康状态。无监督学习方法则通过聚类分析和降维技术&…