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

news2024/11/15 20:04:29

 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 dimension
    for (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 subarray
        myArray[i] = nullptr;
    }
    delete [] myArray; // Delete first dimension
    myArray = 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等等。

3.7、使用指针

       指针由于相对容易遭到滥用而声誉不好。因为指针就是内存地址,理论上可以手动修改,甚至做出像下面代码这样可怕的事情来:

char* scaryPointer { (char*)7 };

       这行代码建立了一个指向内存地址7的指针,可能是一个随机垃圾值,或者是在应用在其他地方使用的内存。如果你开始使用不是你想用的内存区域,例如,使用new或者在栈上,最终你会让与对象相联的内存崩溃掉,或者在自由内存空间上管理的内存,程序会执行错误。这样的一个执行错误会以多种方式显现。例如,它会显示为一个无效的结果,因为数据被破坏掉了,或者是硬件触发的异常,因为访问了不存在的内存,或者尝试写受保护的内存。如果你足够幸运,就会得到一个通常以被操作系统进行程序或者C++运行库终止的严重错误,如果你很不幸,那就会得到错误的结果。记住,错误的结果往往比直接终止更可怕。

3.8、指针的思维模型

       有两种方式来考虑指针。更具有数学思维的读者会将指针认为是地址。这种观点使指针易于计算,易于理解。指针在内存中并不神秘;它们只是在内存中对应相应位置的数字。下图展示了一个以地址为基础的世界中的2乘2的网格。

        对空间展示更熟悉的读者可能从“箭头”指针观点获益更多。指针就是对程序说的一种指向层次,“嗨,看这儿。”这种观点,多层指针就成为了数据道路上的单个步骤。下图显示了一个在内存中的图形化的指针观点。

      当你把指针指向某个值时,通过使用*操作符,你在告诉程序更深一层地访问内存。以地址为基础的观点,会认为把指针指向值是在内存中的一个跳跃,跳到指针显示的地址。以图形化的观点,每一个指针指向值都对应到从尾至头的箭头方向所指。

       当你使用&操作符来拿到某个位置的地址,你就是在内存中间接加了一层。以地址为基础的观点,程序注意到位置的数字地址,可以作为一个指针进行存储。在图形化的观点中,&操作符生成了一个新箭头,它的头在表达式的位置结束。箭头的尾部可以被存储为一个指针。

3.9、指针转化

       因为指针只是内存地址(或者是指向某处的箭头),它们在类型上就会很弱。一个指向XML文档的指针与指向一个整数的指针的大小一样。编译器会很容易地把任何指针类型转化为其他指针类型,使用C风格的代码如下:

Document* documentPtr { getDocument() };
char* myCharPtr { (char*)documentPtr };

       当然了,使用这样的指针会有运行时的灾难后果。静态转化提供了相对安全点的转化。编译器拒绝执行把指针静态转化为无关的数据类型:

Document* documentPtr { getDocument() };

char* myCharPtr { static_cast<char*>(documentPtr) }; // BUG! Won't compile

        我们以后会对不同风格的类型转化进行详细讨论。

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

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

相关文章

『功能项目』项目优化【21】

我们打开上一篇20主角身旁召唤/隐藏坐骑的项目&#xff0c; 本章要做的事情如以下几点&#xff1a; 1.优化资源包Resources下的层级分类 2.优化脚本包Scripts下的脚本分类 3.地形Terrain的优化&#xff08;只让主角点击地面移动跳过其他石头山树等其他物体&#xff09; 首…

笔记整理—uboot番外(3)环境变量的作用

环境变量的最大一个作用就是&#xff0c;能够在不修改代码的情况下去影响应用的运行情况。 环境变量的优先级问题&#xff1a;有环境变量的情况下优先使用环境变量&#xff0c;没有环境变量则使用代码中的值&#xff08;全局变量一类的变量&#xff09;。 例如&#xff0c;mach…

随身WiFi实测,真相让你大跌眼镜!随身携带的随身wifi哪个比较好?什么品牌的随身wifi好用?

都说随身wifi坑多&#xff0c;谁买谁是冤大头&#xff01;我还真不信这个邪&#xff01;本次我们对格行、京东云、迅优三款热门随身WiFi进行了开箱测试&#xff0c;实测周期为2个月。今天从外观、网速、续航、售后、适合人群及整体评价等方面进行全面剖析。 一、京东云随身WiFi…

Qt 杨帆起航

这里写自定义目录标题 引入1、Qt安装1.1 OSX1.1.1 HomeBrew 方式安装1.1.2 自己编译 1.2 Windows x、IDEx.1 Clionx.1.1 ui 文件到Qt设计师x.1.2 ui文件更新&#xff0c;为及时调用uiCompile生成或更新cpp文件x.1.3 qt资源文件创建x.1.4 帮助文档的配置 引入 机缘巧合&#xf…

图像缩放操作

图像缩放操作 微信公众号&#xff1a;幼儿园的学霸 在图像处理过程中&#xff0c;有时需要把图像调整到同样大小&#xff0c;便于处理&#xff0c;这时需要用到图像resize()&#xff0c;该函数比较简单&#xff0c;此处对函数中涉及的各种插值方法进行分析。 目录 文章目录 图…

利用Python解析json生成PPT、xmind思维导图教程

文章目录 背景部分json样例PPT生成思维导图生成 背景 通过调用阿里通义听悟接口&#xff0c;对视频进行了语音转写、智能总结等&#xff0c;现在需要解析返回的PPT和思维导图json文件&#xff0c;以可视化的形式进行呈现。关键点在于&#xff1a; PPT生成时&#xff0c;注意用…

【电池专题】软包电池封装工序

铝塑膜成型工序冲坑 铝塑膜成型工序,软包电芯可以根据客户的需求设计成不同的尺寸,当外形尺寸设计好后,就需要开具相应的模具,使铝塑膜成型。 成型工序也叫作冲坑,顾名思义,就是用成型模具在加热的情况下,在铝塑膜上冲出一个能够装卷芯的坑,具体的见下图。 …

推荐4个一键生成 PPT的AI工具,让你畅享智能办公!

对于职场人士来说&#xff0c;ai PPT 工具已经成为了高效办公的一大得力助手 。它可以让你从繁琐的 PPT 制作中解脱出来&#xff0c;把更多的时间放在其他的工作准备上面。并且它们有极大的设计能力&#xff0c;会让我们的PPT变的设计感十足&#xff0c;如果大家正在为PPT制作烦…

【Linux】进程周边:进程概念

&#x1f337;相关专栏&#xff1a;《c学习》《Linux进阶之路》&#x1f337; 全片内容总览&#xff1a; 目录 1.进程基本概念 2.进程的本质&#xff1f;为什么要有进程控制块PCB&#xff1f; 1&#xff09;为什么要有进程控制块PCB&#xff1f; 2&#xff09;进程的本质 …

sqli-labs靶场通关攻略(41-60)

第四十一关 联合查询爆出数据库 但这关考察的时堆叠注入 &#xff0c;我们给他注入一条数据 输入id50即可查到我们注入的数据 第四十二关 看页面似曾相识&#xff0c;上次我们是用注册新用户然后对其他账户进行登录从而造成注入&#xff0c;但这次不能注册新用户了 存在堆叠注…

leetcode 1645 Hopper公司查询2(postgresql)

需求 表: Drivers -------------------- | Column Name | Type | -------------------- | driver_id | int | | join_date | date | -------------------- driver_id是该表的主键。 该表的每一行均包含驾驶员的ID以及他们加入Hopper公司的日期。 表: Rides ---------------…

【JAVA入门】Day27 - 单列集合体系结构综述

【JAVA入门】Day27 - 单列集合体系结构 文章目录 【JAVA入门】Day27 - 单列集合体系结构1.1 Collection 集合的基本方法1.2 Collection 集合的遍历方式1.2.1 迭代器遍历1.2.2 增强 for 遍历1.2.3 利用 Lambda 表达式进行遍历 1.3 List 集合的基本方法1.4 List 集合的遍历方式 J…

云手机怎样简化海外社媒平台运营

随着越来越多的卖家希望拓展海外市场&#xff0c;运营TikTok、Facebook等社交媒体平台已经成为吸引流量和促进销售的重要手段。然而&#xff0c;在管理海外社媒账号的过程中&#xff0c;许多人会面临网络连接的问题。这时&#xff0c;使用一款高效便捷的云手机工具就显得尤为便…

企业财税自动化解决方案案例分享与经验总结

数字经济时代&#xff0c;企业在财税管理方面面临着越来越多的挑战&#xff0c;作为企业运营的核心部分&#xff0c;其效率和准确性直接关系到企业的财务健康和决策效率。为全面提升财务管理工作的效率和质量&#xff0c;推动业财融合&#xff0c;许多企业开始探索&#xff0c;…

ML17_变分推断01:KL散度、ELBO

1. KL散度 KL散度&#xff08;Kullback-Leibler divergence&#xff09;&#xff0c;也称为相对熵&#xff08;relative entropy&#xff09;&#xff0c;是由Solomon Kullback和Richard Leibler在1951年引入的一种衡量两个概率分布之间差异的方法。KL散度不是一种距离度量&am…

Flutter的升级和降级步骤

升级 1.版本升级 // 升级到指定版本 flutter upgrade 版本号 // 升级到最新版本 flutter upgrade 2. 更新开发配置 启动 Android Studio。 打开 Settings 对话框&#xff0c;查看 SDK Manager。 如果你已经打开了一个项目&#xff0c;请打开 Tools > SDK Manager。 如果…

设置Virtualbox虚拟机共享文件夹

由于工作环境的原因&#xff0c;选择Virtualbox的方式安装虚拟操作系统&#xff0c;常用的操作系统为ubuntu&#xff0c;不知道道友是否也曾遇到这样的问题&#xff0c;就是虚拟机和主机进行文件拖拽的时候&#xff0c;会因为手抖造成拖拽失败&#xff0c;虚拟机界面显示大个的…

CCSI: 用于无数据类别增量学习的持续类别特定印象|文献速递--基于深度学习的医学影像病灶分割

Title 题目 CCSI: Continual Class-Specific Impression for data-free class incremental learning CCSI: 用于无数据类别增量学习的持续类别特定印象 01 文献速递介绍 当前用于医学图像分类任务的深度学习模型表现出了令人鼓舞的性能。然而&#xff0c;这些模型大多要求…

python 怎样计算字符串的长度

python 计算字符串长度&#xff0c;一个中文算两个字符&#xff0c;先转换成utf8&#xff0c;然后通过计算utf8的长度和len函数取得的长度&#xff0c;进行对比即可知道字符串内中文字符的数量&#xff0c;自然就可以计算出字符串的长度了。 valueu脚本12 length len(value) u…

电车买不了保险?就该车企负责

文 | AUTO芯球 作者 | 雷慢 买电车的真是太糟心了&#xff0c; 来看这个车主&#xff0c;去年保费4200&#xff0c;今年保险公司拒保了&#xff0c; 车主说要投诉&#xff0c;保险公司就扔过来一张1万5的报价单。 你不是要保险吗&#xff0c;买吧&#xff01; 我告诉你们&…