从C++开始的编程生活(8)——内部类、匿名对象、对象拷贝时的编译器优化和内存管理

前言

本系列文章承接C语言的学习,需要有C语言的基础才能学会哦~
第8篇主要讲的是有关于C++的内部类匿名对象对象拷贝时的编译器优化内存管理
C++才起步,都很简单!!


目录

前言

内部类

性质

匿名对象

性质

※对象拷贝时的编译器优化

内存管理

内存分区

​编辑

内核空间

静态区/数据段

常量区/代码段

虚拟进程地址空间

动态内存管理函数

C++内存管理

基本语法

operator new和operator delete函数

new和delete的原理

定位new表达式(placement-new)

※内存池(了解即可,后面会深度学)


内部类

一个类定义在另一个类里,这个类就是内部类。

//简单代码
class A
{public:private:class B{private:int _b;}
}

性质

内部类默认是外部类的友元
本质是一种封装方式。若类B实现出来是为了给类A使用,那么可以把B设置为A的内部类。
内部类受访问限定符限制,被privact和protect修饰的内部类只能被外部类使用。

匿名对象

没有标识符标识的对象为匿名对象,反之为有名对象。

//有名对象,d1为其名
Date d1(1999,9,9);
//匿名对象
Date(2000,1,1);

性质

匿名对象的生命周期只有一行代码。也就是匿名对象构造后,下一步就会被析构(一次性筷子)。
②匿名对象具有常性,只能被const引用
被const引用后,匿名对象的生命周期被延长至与该引用同步。

※对象拷贝时的编译器优化

现代编译器会在不影响代码正确性的情况下,提高效率,在底层进行优化实现。
不同的编译器,优化方式不同,以下优化方式以VS2019的debug为例。
越新的编译器,优化越好,甚至会有跨多行合并优化代码。

例1:隐式类型转换

A aa1 = 1;//隐式类型转换

语法上:该隐式类型转换先以1为参数构造临时对象,在将临时对象拷贝构造给aa1。
实际上:直接以1为参数构造新对象aa1。
从而减少对内存的使用,提高代码运行效率。

例2:传值传参

void func(A aa)
{//·······
}
int main()
{func(1)return 0;
}

语法上:该传值传参先以1为参数构造临时对象,在将临时对象拷贝构造给aa,然后传入func。
实际上:直接以1为参数构造对象aa传入func。
从而减少对内存的使用,提高代码运行效率。

例3:传值返回

A f2()
{A aa;return aa
}int main()
{A aa2 = f2();return 0;
}

语法上:构造f2函数局部域的一个对象aa,然后返回aa时将aa拷贝构造为临时对象,接着临时对象在拷贝构造给aa2。(构造->拷贝->拷贝)。
实际上:构造f2函数局部域的一个对象aa,再直接拷贝给aa2。

内存管理

内存分区

内存分区主要分为四个区(还有其他不常用的区,这里省去):栈区、堆区、静态区和常量区

内核空间

用户代码,不可以读写。

局部变量,参数,返回值,对象,函数调用等等要在栈区开辟栈帧,主要存储临时的、局部的变量(栈区占比不大,M为单位)。栈向下增长,越后开辟的空间地址越小。

malloc、new等动态内存管理开辟的空间,在堆区(占比较大,以G为单位)。堆向上增长,越后开辟的空间地址越大(可能会在动态内存管理时被打乱顺序)

静态区/数据段

全局数据和静态数据放在静态区。

常量区/代码段

存放常量和编译完成的指令

虚拟进程地址空间

地址空间是虚拟的,需要页表等算法进行映射,这个部分知识涉及操作系统。

int a;
static int b = 1;
int main()
{int num[] = {1,2,3,4};static int c = 1;char arr[] = "abcdefg";const char* p1 = "abcdefg";char* p2 = (char*)malloc(sizeof(char) * 10);
}

如上代码
a、b、c存放在静态区
num、arr数组存放在栈区
p2存放在堆区
“abcdefg”存放在常量区

动态内存管理函数

C语言动态内存管理函数 malloc / calloc / realloc / free 依旧可以使用

tips:malloc / calloc / realloc的区别?------>calloc会在malloc的基础上,初始化开辟空间;realloc重新分配更多的空间,也覆盖malloc的功能。

C++内存管理

C++有新的方式进行内存管理,使用 new / delete 操作符进行内存管理。

基本语法

int main()
{//动态申请1个int类型空间int *ptr1 = new int;//动态申请1个int类型空间,并初始化为10int *ptr2 = new int(10);//释放开辟的int类型空间delete ptr1;delete ptr2;//动态申请3个int类型的空间int ptr3 = new int[3];//动态申请3个int类型的空间,并依次初始化为1,2,3int ptr4 = new int[3]{1,2,3};//动态申请5个int类型的空间,并依次初始化为1,2,3,为指定初始化的空间,默认初始化为0int ptr5 = new int[5]{1,2,3};//释放开辟的int类型数组delete[] ptr3;delete[] ptr4;delete[] ptr5;return 0;
}

以上为new和delete的使用,改为malloc和free基本没有区别。

而new开辟自定义类型:

//malloc开辟
A* p1 = (A*)malloc(sizeof(A));
//new开辟
A* p2 = new A;
A* p3 = new A(10);
A* p4 = new A[10];//申请空间,构造10次
A* p5 = new A[2]{1,2};//申请空间,构造2次
A* p6 = new A[2]{p2,p3};//申请空间,构造2次

区别:
new之于malloc,不只是申请空间,还会调用其默认构造函数。
错误时不返回NULL,而是抛出异常。
不需要手动填入申请空间大小

而delete释放自定义类型:

delete p2;
delete p3;
delete[] p4;//申请空间,析构10次
delete[] p5;//申请空间,析构2次
delete[] p6;//申请空间,析构2次

区别:delete之于free,不只是释放空间,还会调用其析构函数。

综上,对于自定义类型,还是优先使用new和delete。

operator new和operator delete函数

这不是对操作符new和delete的重载,它们实际上是两个全局函数使用new和delete时,在底层会调用相应的全局函数

在底层源码中,new实际上是对malloc的再次扩展封装。
malloc错误后会抛出一个nullptr,new会遇到malloc抛出的空指针后,首先执行用户提供的应对措施,如果不提供,就抛出一个异常。(异常为后面的内容,了解即可)。

在底层源码中,delete实际上是对free的再次扩展封装。
进行错误检查等处理后,再通过free释放空间

operator new和operator delete也可以直接调用。

new和delete的原理

调用new:①调用operator new函数,开辟空间。②若开辟自定义类型空间,最后依次调用其默认构造函数。

调用delete:①若是释放自定义类型空间,首先依次调用其析构函数。②调用operator delete函数,释放空间。

定位new表达式(placement-new)

作用是在已分配的原始内存空间调用构造函数初始化一个对象。

A *p1 = (A*)operator new(sizeof(A));
//new + 需构造的指针 + 对象类型 + 初始化参数
new(p1)A(10);

为什么要这样做呢?因为不是new开辟的对象,不可以直接初始化,必须要用这种格式

p1->A(10);//错误的

但是,析构可以直接调用。

p1->~A();

※内存池(了解即可,后面会深度学)

从堆区里一次性开辟出较大的内存空间作为内存池,通过数据结构管理起来,申请空间从内存池取出,可以减少频繁申请堆区,因为在堆区只能依次申请空间,效率低。

❤~~本文完结!!感谢观看!!接下来更精彩!!欢迎来我博客做客~~❤

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

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

相关文章

MT5追大速率回测BUG

将MT5策略测试器中的回测速率调到最大(最快速度),**确实非常容易导致出现不符合策略逻辑的秒级成交(闪电交易)**。这并非MT5的“bug”,而是由**回测引擎的工作方式**与**策略代码的编写方法**在高速运行下不匹配所导致的。 --- ### 为什么最大速率会导致问题? MT5回测…

[数据结构——lesson10.堆及堆的调整算法]

引言 上节我们学习完二叉树后[数据结构——lesson9.二叉树],这节我们将学习数据结构——堆 学习目标 1.堆的概念及结构 堆是一种特殊的完全二叉树结构,在计算机科学和数据结构中广泛应用,特别是在堆排序算法和优先队列的实现中,…

九识智能与北控北斗合作研发的L4级燃气超微量高精准泄漏检测无人车闪耀服贸会,守护城市安全

2025年9月10日至14日,2025年中国国际服务贸易交易会将于北京首钢园举办。在这场国际盛会上,九识智能与北京北控北斗科技投资有限公司(以下简称“北控北斗”)合作研发的L4级燃气超微量高精准泄漏检测无人车及相关系统解决方案&…

【C语言入门】手把手教你实现顺序栈

栈是计算机科学中最基础且重要的数据结构之一,它遵循"后进先出"(LIFO)的原则。想象一下一叠盘子,你只能从最上面取放,这就是栈的直观体现。本文将用C语言带你一步步实现一个顺序栈,即使你是编程小…

北斗导航 | ARAIM(高级接收机自主完好性监测)算法在民航LPV-200进近中的具体实现流程

要详细说明ARAIM(高级接收机自主完好性监测)算法在民航LPV-200进近中的具体实现流程,需结合ARAIM的核心逻辑(多星座融合、多假设解分离、风险优化分配)与LPV-200的严格要求(垂直保护级VPL≤35米、垂直告警限VAL=35米、有效监测门限EMT≤15米等),以下是 step-by-step 的…

AIPex:AI + 自然语言驱动的浏览器自动化扩展

AIPex:AI + 自然语言驱动的浏览器自动化扩展 引言 一、快速上手 1.1 安装AIPex扩展 1.2 首次配置 1.3 界面介绍 第二章:30+工具详解 2.1 标签页管理工具集 🗂️ **get_all_tabs - 全局标签页概览** 🎯 **switch_to_tab - 智能标签页切换** 📋 **标签页批量操作** 📋 …

机器学习模型可信度与交叉验证:通俗讲解

先从一个故事说起:农场里的火鸡科学家,观察了一年发现“每天上午11点必有食物”,结果感恩节当天,它没等到食物,反而成了人类的食物。这个故事告诉我们:只靠过去的经验下结论,很可能出错——机器…

HTML5和CSS3新增的一些属性

1、HTML5新增特性这些新特性都有兼容性问题&#xff0c;基本是IE9以上版本浏览器才支持1&#xff09;新增语义化标签2&#xff09;新增多媒体标签音频&#xff1a;<audio>视频&#xff1a;<video>&#xff08;1&#xff09;视频<video>---尽量使用mp4格式<…

Redis的RedLock

RedLock算法深度解析RedLock是Redis作者针对分布式环境设计的多节点锁算法&#xff0c;核心目标是解决单点Redis在分布式锁场景中的可靠性缺陷。传统方案的局限性单节点Redis锁的问题单点故障&#xff1a;单个Redis实例宕机导致所有锁服务不可用可靠性不足&#xff1a;无法保证…

SpringMVC @RequestMapping的使用演示和细节 详解

目录 一、RequestMapping是什么&#xff1f; 二、RequestMapping 的使用演示 1.RequestMapping在方法上的使用&#xff1a; 2.RequestMapping同时在类和方法上使用&#xff1a; 3.RequestMapping指定请求参数&#xff1a; 4.RequestMapping使用Ant风格URL&#xff1a; 5.Requ…

flutter项目 -- 换logo、名称 、签名、打包

1、换logo, 透明底&#xff0c;下面5个尺寸&#xff0c;需要UI设计2、换名没配置型的改名方式如下 打开app/src/main/AndroidManifest.xml3、签名 运行 flutter doctor -vD:\project\Apk\keystore 自己建立的keystore文件夹&#xff0c; 注意命令后是 megoai-release-key(自…

【贪心算法】day9

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的贪心算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&#xff…

linux C 语言开发 (八) 进程基础

文章的目的为了记录使用C语言进行linux 开发学习的经历。开发流程和要点有些记忆模糊&#xff0c;赶紧记录&#xff0c;防止忘记。 相关链接&#xff1a; linux C 语言开发 (一) Window下用gcc编译和gdb调试 linux C 语言开发 (二) VsCode远程开发 linux linux C 语言开发 (…

从零学算法1094

1094.拼车 车上最初有 capacity 个空座位。车 只能 向一个方向行驶&#xff08;也就是说&#xff0c;不允许掉头或改变方向&#xff09; 给定整数 capacity 和一个数组 trips , trips[i] [numPassengersi, fromi, toi] 表示第 i 次旅行有 numPassengersi 乘客&#xff0c;接他…

B2B企业营销型AI Agent服务商推荐:谁更专业?如何选型?

一、引言&#xff1a;为什么B2B企业需要营销型AI Agent&#xff1f;在当前竞争激烈的B2B市场中&#xff0c;企业普遍面临几大挑战&#xff1a;线索获取难&#xff1a;获客成本持续上升&#xff0c;高质量线索难以筛选。销售周期长&#xff1a;从初步接触到签单&#xff0c;往往…

算法-双指针5.6

目录 &#x1f33f;力扣611-有效三角形得个数 &#x1f9ca;题目链接&#xff1a;https://leetcode.cn/problems/valid-triangle-number/description/ &#x1f9ca;题目描述&#xff1a;​编辑 &#x1f9ca;解题思路&#xff1a; &#x1f9ca;解题代码&#xff1a; &a…

超参数自动化调优指南:Optuna vs. Ray Tune 对比评测

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;注册即送-H卡级别算力&#xff0c;80G大显存&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生更享专属优惠。 引言&#xff1a;从"手动炼丹"到"自动化…

软考-局域网基础考点总结

这篇文章用于整理软考网络相关的知识点&#xff0c;囊括了详细的局域网基础的考点&#xff0c;能够让你认真备考&#xff0c;基础知识一网打尽&#xff0c;让后续的学习更加通畅~ 第一部分&#xff1a;OSI七层参考模型 OSI(Open System Interconnection)模型是一个理论框架&am…

Node.js核心模块介绍

1. fs 模块fs&#xff08;File System&#xff09;模块允许对文件系统进行操作&#xff0c;提供了文件读写、文件夹操作等功能。fs 支持同步和异步两种 API。1.1. 常用方法读取文件&#xff1a;异步: fs.readFile()同步: fs.readFileSync()写入文件&#xff1a;异步: fs.writeF…

缓存三大劫攻防战:穿透、击穿、雪崩的Java实战防御体系(二)

第二部分&#xff1a;缓存击穿——热点key过期引发的“DB瞬间高压” 缓存击穿的本质是“某个热点key&#xff08;高并发访问&#xff09;突然过期”&#xff0c;导致大量请求在同一时间穿透缓存&#xff0c;集中冲击DB&#xff0c;形成“瞬间高压”。 案例3&#xff1a;电商秒杀…