C++中低级内存操作
C++中低级内存操作
C++相较于C有一个巨大的优势,那就是你不需要过多地担心内存管理。如果你使用面向对象的编程方式,你只需要确保每个独立的类都能妥善地管理自己的内存。通过构造和析构,编译器会帮助你管理内存,告诉你什么时候需要进行内存操作。将内存管理隐藏在类中显著提高了可用性,这一点在标准库类中得到了很好的体现。
然而,在某些应用程序或遗留代码中,你可能会遇到需要更低级别地操作内存的情况。无论是出于遗留代码、效率、调试还是好奇心,了解如何操作原始字节总是有帮助的。
指针
C++编译器会使用指针的声明类型来允许你进行指针算术。如果你声明了一个指向整数的指针并将其增加1,那么这个指针在内存中前进的距离是整数的大小,而不是一个单一的字节。这种操作对数组最有用,因为数组包含的数据是类型一致且在内存中连续的。
例如,假设你在自由存储区声明了一个整数数组:
int* myArray { new int[8] };
你可能已经熟悉了以下用于设置索引为2的值的语法:
myArray[2] = 33;
通过使用指针算术,你也可以使用以下等效的语法,该语法获取到myArray“向前两个整数”处的内存的指针,然后解引用它以设置该值:
*(myArray + 2) = 33;
作为访问单个元素的另一种语法,指针算术看起来可能不太吸引人。但其真正的力量在于,像myArray+2这样的表达式仍然是一个指向整数的指针,因此可以表示一个更小的整数数组。
让我们通过一个使用宽字符串的例子来看看。宽字符串支持所谓的Unicode字符,以表示例如日语字符串。wchar_t类型是一个可以容纳这种Unicode字符的字符类型,并且通常比char要大;也就是说,它不仅仅是一个字节。要告诉编译器一个字符串字面量是一个宽字符串字面量,可以在其前面加上一个L。
例如,假设你有以下宽字符串:
const wchar_t* myString { L"Hello, World" };
进一步假设你有一个函数,该函数接受一个宽字符串并返回一个包含输入字符串大写版本的新字符串:
wchar_t* toCaps(const wchar_t* text);
请记住,C风格的字符串是以零结尾的,即它们的最后一个元素包含\0。因此,没有必要在函数中添加一个大小参数来指定输入字符串的长度。该函数只需不断地迭代字符串的各个字符,直到遇到\0字符为止。
通过将myString传递给toCaps()函数,你可以将其全部转换为大写。然而,如果你只想部分地大写化myString,你可以使用指针算术来仅引用字符串的后一部分。下面的代码通过仅向指针加7来调用toCaps()函数,以处理宽字符串中的“World”部分,尽管wchar_t通常超过1个字节:
toCaps(myString + 7);
另一个有用的指针算术应用涉及到减法。从同一类型的另一个指针中减去一个指针会给你两个指针之间指向类型的元素数量,而不是它们之间的绝对字节数。
自定义内存管理
在你将遇到的99%(有人可能会说100%)的情况中,C++中的内置内存分配功能是足够的。在幕后,new和delete完成了以适当大小的块分配内存、维护可用内存区域列表以及在删除时将内存块释放回该列表的所有工作。但是,当资源约束非常紧张,或者在非常特殊的条件下,例如管理共享内存,实施自定义内存管理可能是一个可行的选项。不用担心,这并不像听起来那么可怕。
基本上,自己管理内存意味着类会分配一大块内存,并根据需要将该内存分配出去。这种方法有什么好处呢?管理自己的内存可能会减少开销。当你使用new来分配内存时,程序还需要预留一小部分空间以记录分配了多少内存。这样,当你调用delete时,可以释放适当数量的内存。对于大多数对象,开销比分配的内存小得多,因此影响甚微。然而,对于小对象或有大量对象的程序,开销可能会产生影响。当你自己管理内存时,你可能会提前知道每个对象的大小,因此你可能能够避免每个对象的开销。对于大量的小对象来说,差异可能是巨大的。
执行自定义内存管理需要重载new和delete操作符。
垃圾收集
在支持垃圾收集的环境中,程序员很少(如果有的话)明确释放与对象关联的内存。相反,不再有任何引用的对象将在某个时候被运行时库自动清理。垃圾收集没有像在C#和Java中那样内置到C++语言中。在现代C++中,你使用智能指针来管理内存,而在遗留代码中,你将看到通过new和delete在对象级别进行内存管理。
诸如shared_ptr这样的智能指针提供了与垃圾收集内存非常相似的东西;也就是说,当某一资源的最后一个shared_ptr实例被销毁时,该资源也会在那个时刻被销毁。在C++中实现真正的垃圾收集是可能但不容易的,但释放自己从释放内存的任务中可能会引入新的问题。
标记-清除垃圾收集
一种垃圾收集的方法被称为“标记-清除”(Mark and Sweep)。在这种方法下,垃圾收集器会周期性地检查程序中的每一个指针,并标注哪些内存仍然在使用中。在周期结束时,任何没有被标记的内存被认为是不再使用的,并会被释放。在C++中实现这样的算法并不简单,如果做错了,可能比使用delete更容易出错!
尽管在C++中已经有了安全且简单的垃圾收集机制的尝试,但即使有了完美的C++垃圾收集实现,也不一定适用于所有应用程序。垃圾收集的缺点包括:
- 当垃圾收集器正在运行时,程序可能变得无响应。
- 在使用垃圾收集器的情况下,你会遇到所谓的“非确定性析构函数”。因为一个对象在被垃圾收集之前不会被销毁,所以析构函数在对象离开其作用域时不会立即执行。这意味着,由析构函数完成的资源清理(例如关闭文件、释放锁等)直到未来某个不确定的时间才会被执行。
编写垃圾收集机制是非常困难的。你很可能会做错,而且很可能会很慢。因此,如果你确实想在你的应用程序中使用垃圾收集内存,我强烈建议你研究现有的专门的垃圾收集库,并重用它们。
对象池
垃圾收集就像是为野餐购买盘子,并将用过的盘子留在院子里,以便某人在某个时候将它们捡起来并扔掉。肯定有更环保的内存管理方法。对象池就是回收的等价物。你购买了一定数量的盘子,使用过一个盘子后,你将其清洗,以便以后可以再次使用。
对象池是理想的解决方案,适用于你需要在一段时间内多次使用相同类型的多个对象,并且每次创建都会产生开销的情况。
相关文章:
C++中低级内存操作
C中低级内存操作 C相较于C有一个巨大的优势,那就是你不需要过多地担心内存管理。如果你使用面向对象的编程方式,你只需要确保每个独立的类都能妥善地管理自己的内存。通过构造和析构,编译器会帮助你管理内存,告诉你什么时候需要进…...
Linux硬盘大小查看命令全解析 (linux查看硬盘大小命令)
Linux操作系统是一款广泛应用于服务器和嵌入式设备的操作系统,相比于Windows等其他操作系统,Linux的优点之一就是支持强大的命令行操作。在日常操作中,了解和掌握一些简单但实用的命令可以提高工作效率。比如硬盘大小查看命令,在L…...
什么是供应链金融?
一、供应链金融产生背景 供应链金融兴起的起源来自于供应链管理一个产品生产过程分为三个阶段:原材料 - 中间产品 - 成产品。由于技术进步需求升级,生产过程从以前的企业内分工,转变为企业间分工。那么整个过程演变了如今的供应链管理流程&a…...
Qt之实现支持多选的QCombobox
一.效果 1.点击下拉列表的复选框区域 2.点击下拉列表的非复选框区域 二.实现 QHCustomComboBox.h #ifndef QHCUSTOMCOMBOBOX_H #define QHCUSTOMCOMBOBOX_H#include <QLineEdit> #include <QListWidget> #include <QCheckBox> #include <QComboBox>…...
【UI设计】Figma_“全面”快捷键
目录 1.快捷键与键位(mac与windows)2.基础快捷键3.操作区快捷键3.1视图3.2文字3.3选项3.4图层3.5组件 4.特殊技巧 Figma 是一个 基于浏览器 的协作式 UI 设计工具。【https://www.figma.com/】 Figma Sketch(UI 设计) InVision&a…...
计算机网络(谢希仁)第八版课后题答案(第一章)
1.计算机网络可以向用户提供哪些服务 连通性:计算机网络使上网用户之间可以交换信息,好像这些用户的计算机都可以彼此直接连通一样。 共享:指资源共享。可以是信息、软件,也可以是硬件共享。 2.试简述分组交换的要点 采用了存储转发技术。把报文(要发…...
argparse模块介绍
argparse是一个Python模块:命令行选项、参数和子命令解析器。argparse 模块可以让人轻松编写用户友好的命令行接口。程序定义了所需的参数,而 argparse 将找出如何从 sys.argv (命令行)中解析这些参数。argparse 模块还会自动生成…...
分布式、集群、微服务
分布式是以缩短单个任务的执行时间来提升效率的;而集群则是通过提高单位时间内执行的任务数来提升效率。 分布式是指将不同的业务分布在不同的地方。 集群指的是将几台服务器集中在一起,实现同一业务。 分布式中的每一个节点,都可以做集群…...
Android Studio的debug和release模式及签名配置
Android Studio的两种模式及签名配置 使用Android Studio 运行我们的app,无非两种模式:debug和release模式。 https://www.cnblogs.com/details-666/p/keystore.html...
【深蓝学院】手写VIO第8章--相机与IMU时间戳同步--笔记
0. 内容 1. 时间戳同步问题及意义 时间戳同步的原因:如果不同步,由于IMU频率高,可能由于时间戳不同步而导致在两帧camera之间的时间内用多了或者用少了IMU的数据,且时间不同步会导致我们首尾camera和IMU数据时间不同,…...
【Java集合类面试二十一】、请介绍TreeMap的底层原理
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 面试官:请介绍TreeMap的底层原理…...
Go语言Channel
在本教程中,我们将讨论Channel以及 Goroutines 如何使用Channel进行通信。 什么是Channel Channel可以被认为是 Goroutine 用来进行通信的管道。与水在管道中从一端流向另一端的方式类似,可以使用Channel从一端发送数据并从另一端接收数据。 声明Chan…...
java 编译 引用 jar 包进行编译和执行编译后的class文件
编译java文件 javac -encoding UTF-8 -Djava.ext.dirs./ -d . ./FtpTest.java 执行编译class文件 java -Djava.ext.dirs./ com.util.FtpTest com.util为包路径...
Linux系统之部署Tale个人博客系统
Linux系统之部署Tale个人博客系统 一、Tale介绍1.1 Tale简介1.2 Tale特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本 四、部署Tale个人博客系统4.1 下载Tale源码4.2 查看Tale源码目录4.3 查看安装脚本内…...
【跟小嘉学 Rust 编程】三十三、Rust的Web开发框架之一: Actix-Web的基础
系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...
算法通关村|黄金挑战|K个一组进行反转
K个一组进行反转 1.头插法 public ListNode reverseKGroup(ListNode head, int k) {ListNode dummyNode new ListNode(0);dummyNode.next head;ListNode cur head;// 计算链表长度int len 0;while (cur ! null) {len;cur cur.next;}// 计算有几组int n len / k;ListNod…...
【Android Studio】工程中文件Annotate with Git Blame 不能点击
问题描述 工程文件中想要查看代码提交信息但是相关按钮不可点击 解决方法 Android Studio -> Preferences -> Version Control-> 在Unregistered roots里找到你想要的工程文件 点击左上角➕号 然后右下角Apply即可...
Ant Design Vue
2222222222222...
ATA-P2010压电叠堆功率放大器-直流偏置对压电叠堆测试的重要性
随着科技的发展和应用领域的扩展,压电技术在许多领域中得到了广泛的应用。在压电器件的研究和开发过程中,压电叠堆测试是非常重要的一环。本文通过对功率放大器的直流偏置功能在压电叠堆测试中的应用进行了深入研究,探讨了功率放大器直流偏置…...
短视频矩阵系统搭建/源头----源码
一、智能剪辑、矩阵分发、无人直播、爆款文案于一体独立应用开发 抖去推----主要针对本地生活的----移动端(小程序软件系统,目前是全国源头独立开发),开发功能大拆解分享,功能大拆解: 7大模型剪辑法(数学阶乘ÿ…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
