类和对象最终与内存管理上

devtools/2024/9/25 3:58:23/

在这里插入图片描述

嗨喽,大家好呀,今天阿鑫给大家带来类和对象最终章以及内存管理上!经过半个多月的艰苦奋斗我们终于将要翻过类和对象这座山,下面让我们开始今天的博客学习吧!

类和对象最终与内存管理上

  1. 匿名对象
  2. c++内存管理方式
  3. operator new与operator delete函数
  4. 利用new实现一个简单链表

1.匿名对象

class A
{
public:A(int b = 0):_a(b),_a1(b),_a2(b){cout << "A(int b = 0)" << endl;}//explicit//单参数类型转换/*A(int a):_a(a){cout << "A(int a)" << endl;}*///多参数类型转换A(int m, int n):_a1(m), _a2(n){cout << "A(int m, int n)" << endl;_a = 0;}A(const A& aa)//拷贝构造:_a(aa._a){cout << "A(const A& aa)" << endl;}~A(){cout << "~A()" << endl;_a = -1;_a1 = -1;_a2 = -1;}private:int _a;int _a1;int _a2;};
A(2);

注意:匿名对象,生命周期只存在这一行

我们补充一下析构的顺序以及全局变量和静态变量构造与main函数的先后关系

  1. 对于后定义的对象先进行析构。
  2. 全局对象在main函数前就构造了,而静态对象生命周期是全局的但是第一次调用时才会进行构造,只会初始化一次

在开始我们的讲解之前,我们先来回顾一下c和c++的程序内存空间划分,并且用一道题目来回顾一下我们之前学习过的内容
在这里插入图片描述

在这里插入图片描述

答案:CCCAA
AAADAB

在这里插入图片描述

有问题的同学自行阅读这张图,相信就能解决你的问题。

2.C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

2.1 new/delete操作内置类型

下面给出示范

int main
{//对于内置类型int* p1 = new int[10];int* p2 = new int[10];delete p1;delete[] p2;return 0}

默认不初始化,但是可以初始化

对于自定义类型

class A
{
public:A(int b = 0):_a(b){cout << "A(int b = 0)" << endl;}//explicit//单参数类型转换/*A(int a):_a(a){cout << "A(int a)" << endl;}*///多参数类型转换A(int m, int n):_a1(m), _a2(n){cout << "A(int m, int n)" << endl;_a = 0;}A(const A& aa)//拷贝构造:_a(aa._a){cout << "A(const A& aa)" << endl;}~A(){cout << "~A()" << endl;}private:int _a;int _a1;int _a2;};int main()
{A* p1 = new A(3);delete p1;A* p2 = new A({4,5});delete p2;A* p3 = new A;//不传参调用默认构造delete p3;A* p4 = new A[10]{ 1,2,3,4,5 };//隐式类型转换delete[] p4;A* p5 = new A[10]{ 1,2,3,4,{5,6} };delete[] p5;return 0;
}

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

3 .operator new与operator delete函数

3 .1operator new与operator delete函数

new和delete是用户进行动态内存电请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

A* p1 = new A;
delete p1;

当我们在执行这两句代码时
第一句会转换成

operator new->(malloc)+构造函数

第二句会转换成

析构 + operator delete

并且是由顺序的,我们可以通过汇编语言来看到这个过程
在这里插入图片描述
在这里插入图片描述

3 .2operator new和构造函数的区别

在这里插入图片描述

当您在C++中使用new关键字来创建一个对象(比如一个栈类实例)时,以下是发生的事情的简要概述:

需要注意的是:内存分配时并没有对成员变量初始化,是编译器通过计算判断出需要创建的成员变量内存需要的大小,这个内存大小通常是根据对象的成员变量所确定,等到构造函数时才会真正对成员变量初始化

1.内存分配:new操作符首先调用operator new来为对象分配足够的内存空间。这个空间的大小通常等于对象的所有成员变量所占用的空间的总和,再加上任何可能由于内存对齐而产生的填充。

2.构造函数调用:一旦内存被成功分配,new操作符会调用对象的构造函数。构造函数负责初始化对象的成员变量。这可能包括为成员变量设置初始值,以及执行任何必要的初始化代码(比如为栈上的资源开辟空间)。

对于栈类来说,构造函数可能会执行以下操作:

初始化成员变量,比如栈顶指针或栈的大小。
为栈分配内部存储空间,这通常涉及到动态内存分配(比如使用new为数组分配空间)。
设置栈的初始状态(比如将栈顶指针设置为指向栈的底部)。
重要的是要理解,operator new只负责分配内存,而对象的实际初始化工作是由构造函数完成的。构造函数可以执行任何必要的初始化步骤,包括为对象的成员变量或内部资源分配空间。

下面是一个简单的栈类的例子,它展示了构造函数如何为栈的内部数组分配空间:

class Stack {  
private:  int* elements; // 指向存储栈元素的数组的指针  size_t capacity; // 栈的容量  size_t size; // 栈中当前元素的数量  public:  // 构造函数  Stack(size_t cap) : capacity(cap), size(0) {  // 使用 new 为存储栈元素的数组分配内存  elements = new int[capacity];  // 此时,elements 指向一个包含 capacity 个 int 的数组,用于存储栈元素  }  // 析构函数  ~Stack() {  // 释放存储栈元素的数组所占用的内存  delete[] elements;  }  // 其他栈操作函数...  void push(int value) {  if (size < capacity) {  elements[size++] = value;  } else {  // 处理栈满的情况,可能抛出异常或自动扩容等  }  }  int pop() {  if (size > 0) {  return elements[--size];  } else {  // 处理栈空的情况,可能抛出异常等  }  }  // ... 其他成员函数 ...  
};

在这个例子中:

Stack 类的成员变量包括一个指向 int 数组的指针 elements、一个表示栈容量的 size_t 类型变量 capacity 和一个表示当前栈大小的 size_t 类型变量 size
构造函数接受一个 cap 参数,并使用 new 为 elements 分配一个大小为 cap 的 int 数组。这个数组用于存储栈中的元素。
析构函数使用 delete[] 释放 elements 指向的数组所占用的内存。
push 和 pop 方法操作这个动态分配的数组,以实现栈的基本功能。
所以,operator new 只负责分配 Stack 对象本身的内存,而栈中实际存储元素的数组是通过构****造函数内部额外的 new 调用分配的。这允许我们根据需要在运行时动态地调整栈的大小。

4. 利用new实现一个简单链表

struct ListNode
{struct ListNode* _next;int _val;struct ListNode(int val):_next(nullptr),_val(val){}};
void func()
{struct ListNode* node1 = new struct ListNode(1);//	//得到的是一个ListNode类的指针,要用指定类型的指针接受//	//new失败了会抛异常,不需要再检查返回值struct ListNode* node2 = new struct ListNode(2);struct ListNode* node3 = new struct ListNode(3);node1->_next = node2;node2->_next = node3;delete node1;delete node2;delete node3;
}
int main()
{try{func();}catch (const exception& e){cout << e.what() << endl;}return 0;
}

今天的博客就分享到这里啦!期待我们的下一次相遇,觉得阿鑫博客写的还可以的记得留下你的三连,拜拜!


http://www.ppmy.cn/devtools/4318.html

相关文章

Python框架django项目

创建一个 Django 项目是一个很好的方式来学习和实践 Python web 开发。以下是创建 Django 项目的基本步骤&#xff1a; 步骤&#xff1a; 安装 Django&#xff1a; 首先&#xff0c;确保你已经安装了 Python。然后&#xff0c;使用 pip 安装 Django&#xff1a; pip install d…

CDP7 下载安装 Flink Percel 包

下载链接&#xff1a;https://www.cloudera.com/downloads/cdf/csa-trial.html 点击后选择版本&#xff0c; 然后点击download now&#xff0c;会有一个协议&#xff0c;勾选即可&#xff0c;然后就有三个文件列表&#xff0c; 我这里是已经注册登录的状态&#xff0c;如果没…

Django中的实时通信:WebSockets与异步视图的结合

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在现代Web应用程序中&#xff0c;实时通信已经成为了必不可少的功能之一。无论是在线聊天、…

Python 天气预测

Python天气预测通常涉及到数据采集、数据预处理、选择和训练模型、以及预测和可视化等步骤。以下是使用Python进行天气预测的一般流程&#xff1a; 数据采集 使用爬虫技术从天气网站&#xff08;如Weather Underground、中国天气网等&#xff09;爬取历史天气数据&#xff0c…

【人工智能基础】状态空间搜索

状态空间法 状态空间&#xff1a;一个问题全部可能的状态以及其关系的集合。 状态空间图&#xff1a;以图的形式表示问题的状态空间&#xff0c;节点对应状态&#xff0c;边对应状态转移算子&#xff0c;边上的权对应转移所需的代价 问题的解&#xff1a;是从最开始状态到目…

大创项目推荐 深度学习YOLO图像视频足球和人体检测 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络4 Yolov5算法5 数据集6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习YOLO图像视频足球和人体检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非…

docker安装并跑通QQ机器人实践(2)-签名服务器bs-qsign搭建

在前文中&#xff0c;我们详尽阐述了QQ机器人的搭建过程及其最终实现的各项功能展示。接下来&#xff0c;我们将转向探讨该项目基于Docker构建服务的具体实践。本篇将以QQ机器人签名服务——qsign为起点&#xff0c;逐步展开论述。 1 获取和运行 xzhouqd/qsign:8.9.63 镜像 1.…

Java如何用EasyExcel插件对Excel进行数据导入和数据导出

文章目录 一、EasyExcel的示例导入依赖创建实体类数据导入和导出 二、EasyExcel的作用三、EasyExcel的注解 EasyExcel是一个阿里巴巴开源的excel处理框架&#xff0c;它以使用简单、节省内存著称。在解析Excel时&#xff0c;EasyExcel没有将文件数据一次性全部加载到内存中&…