【C++】内存管理

这篇具有很好参考价值的文章主要介绍了【C++】内存管理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、C/C++内存分布

我们以前学习过C语言中内存管理方式,我们先看以下代码回顾一下:

		int globalVar = 1;
		static int staticGlobalVar = 1;
		
		void Test()
		{
			static int staticVar = 1;
		
			int localVar = 1;
		
			int num1[10] = { 1, 2, 3, 4 };
		
			char char2[] = "abcd";
		
			const char* pChar3 = "abcd";
		
			int* ptr1 = (int*)malloc(sizeof(int) * 4);
			free(ptr1);
		}

首先 globalVar 定义在全局域,是全局变量,所以它存在静态区(数据段);staticGlobalVarstaticVar 是用了 static 修饰,所以它们也存在静态区;

localVar num1char2pChar3 ptr1 都是定义在局部域,所以它们存在栈区;

那么*char2 在哪里呢?其实它还是在栈区上,首先我们知道,C/C++中程序内存区域划分大致是下图这样:

【C++】内存管理,c++,jvm,开发语言,c语言

  1. 栈又叫堆栈 --非静态局部变量/函数参数/返回值等等,栈是向下增长的。
  2. 堆用于程序运行时动态内存分配,堆是可以上增长的。
  3. 数据段(静态区) --存储全局数据和静态数据。
  4. 代码段(常量区)–可执行的代码/只读常量

char2pChar3ptr1 在内存区域中的划分如下:

【C++】内存管理,c++,jvm,开发语言,c语言
首先 “abcd\0” 这段字符串存在常量区中,char char2[] = "abcd"; 是将这段字符串拷贝到 char2 这个数组中,所以 *char2 还是在栈区上;pChar3 也在栈区上,但是 *pChar3 却在常量区上,因为 pChar3 是指向 “abcd\0” 的,所以解引用之后就是找到这段字符串;ptr1 也是定义在栈区上的指针,但是它指向的内容是在堆上的,所以 *ptr1 是在堆上。

二、C++ 内存管理方式

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

1. new/delete操作内置类型

		void Test()
		{
			// 动态申请一个int类型的空间
			int* ptr4 = new int;
		
			// 动态申请一个int类型的空间并初始化为10
			int* ptr5 = new int(10);
		
			// 动态申请3个int类型的空间
			int* ptr6 = new int[3];
			delete ptr4;
			delete ptr5;
			delete[] ptr6;
		}

注意:申请和释放单个元素的空间,使用 newdelete 操作符,申请和释放连续的空间,使用 new[]delete[] ,注意:匹配起来使用。

2. new和delete操作自定义类型

new/delete 和 malloc/free 最大区别是 new/delete 对于自定义类型除了开空间还会调用构造函数和析构函数,例如以下代码:

		class A
		{
		public:
			A(int a = 0)
				:_a(a)
			{
				cout << "A(int a = 0)" << endl;
			}
		
			~A()
			{
				cout << "~A()" << endl;
			}
		
		private:
			int _a;
		};

new/delete 对自定义类型的使用如下:

		int main()
		{
			// 调用构造函数,使用缺省值初始化
			A* ptr1 = new A;
			delete ptr1;      // 调用析构函数
		
			// 调用构造函数,使用 10 初始化
			A* ptr2 = new A(10);
			delete ptr2;     // 调用析构函数
		
			// 申请3个A类型的空间
			A* ptr3 = new A[3];
			delete[] ptr3;  // 调用析构函数
		
			return 0;
		}

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

三、new 和 delete 的实现原理

1. 内置类型

如果申请的是内置类型的空间,new 和 malloc,delete和free基本类似,不同的地方是:new/delete 申请和释放的是单个元素的空间,new[] 和 delete[] 申请的是连续空间,而且 new 在申请空间失败时会抛异常,malloc 会返回NULL。

2. 自定义类型

new的原理

  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理

  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间

new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用 operator new 函数完成N个对象空间的申请
  2. 在申请的空间上执行N次构造函数

delete[]的原理

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用operator delete 来释放空间

四、定位new表达式(placement-new) (了解)

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

使用场景: 定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

		class A
		{
		public:
			A(int a = 0)
				: _a(a)
			{
				cout << "A():" << endl;
			}
			~A()
			{
				cout << "~A():" << endl;
			}
		
		private:
			int _a;
		};

定位new/replacement new 的使用:

		int main()
		{
			// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
			A* p1 = (A*)malloc(sizeof(A));
		
			// 显式调用构造函数
			// 注意:如果A类的构造函数有参数时,此处需要传参
			new(p1)A;    
		
			// 显式调用析构函数
			p1->~A();
			free(p1);
		
		
			A* p2 = (A*)operator new(sizeof(A));
			new(p2)A(10);
			p2->~A();
			operator delete(p2);
		
			return 0;
		}

五、 malloc/free 和 new/delete 的区别

malloc/free 和 new/delete 的共同点是:都是从堆上申请空间,并且需要用户手动释放。 不同的地方是:文章来源地址https://www.toymoban.com/news/detail-626164.html

  1. malloc 和 free 是函数,new 和 delete 是操作符。
  2. malloc 申请的空间不会初始化,new 可以初始化。
  3. malloc 申请空间时,需要手动计算空间大小并传递,new 只需在其后跟上空间的类型即可,如果是多个对象,[] 中指定对象个数即可。
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型。
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常。
  6. 申请自定义类型对象时,malloc/free 只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。

到了这里,关于【C++】内存管理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM—内存管理(运行时数据区)、垃圾回收

    当JVM类加载器加载完字节码文件之后,会交给执行引擎执行,在执行的过程中会有一块JVM内存区域来存放程序运行过程中的数据,也就是我们图中放的运行时数据区,那这一块运行时数据区究竟帮我们做了哪些工作?我们常说的线上内存泄漏和内存溢出是因为什么?我们今儿

    2024年02月13日
    浏览(40)
  • JVM内存管理、内存分区:堆、方法区、虚拟机栈、本地方法栈、程序计数器

    线程共享 堆         存放 实例 ,字符串常量(直接引用),静态变量,线程分配缓冲区(TLAB线程私有)。 垃圾收集器 管理的区域 方法区         非堆,和堆相对的概念。存储已被虚拟机加载的 类型信息 、常量、静态变量、即时编译器编译后的代码缓存等数据,内

    2024年02月10日
    浏览(40)
  • JVM | 垃圾回收器(GC)- Java内存管理的守护者

    在编程世界中, 有效的内存管理 是至关重要的。这不仅确保了应用程序的稳定运行,还可以大大提高性能和响应速度。作为世界上最受欢迎的编程语言之一,通过Java虚拟机内部的垃圾回收器组件来自动管理内存,是成为之一的其中一项必不可少的技术点。 在许多传统的编程

    2024年02月09日
    浏览(50)
  • 深入探讨Java虚拟机(JVM):执行流程、内存管理和垃圾回收机制

    目录 什么是JVM? JVM 执行流程 JVM 运行时数据区 堆(线程共享) Java虚拟机栈(线程私有) 什么是线程私有? 程序计数器(线程私有) 方法区(线程共享) JDK 1.8 元空间的变化 运行时常量池 内存布局中的异常问题 1.  Java堆溢出 2.  虚拟机栈和本地方法栈溢出 JVM 类加载 1.

    2024年02月09日
    浏览(45)
  • 【C++内存管理】内存池

    C++17 引入了一个新的内存资源抽象层 - memory_resource 。其主要目的是将内存的分配和回收与具体的数据结构解耦,从而允许开发人员使用不同的内存管理策略,提高内存管理的灵活性。 memory_resource 是一个基类,可以用于创建和配置具有不同内存管理行为的内存池。 1.1 memory_

    2024年02月13日
    浏览(40)
  • C++内存管理(3)——内存池

    利用默认的内存管理操作符 new/delete 和函数 malloc()/free() 在堆上分配和释放内存会有一些额外的开销。 系统在接收到分配一定大小内存的请求时,首先查找内部维护的内存空闲块表,并且需要根据一定的算法(例如分配最先找到的不小于申请大小的内存块给请求者,或者分配

    2024年02月09日
    浏览(40)
  • C++——内存分配与动态内存管理

    🌸作者简介: 花想云 ,在读本科生一枚,致力于 C/C++、Linux 学习。 🌸 本文收录于 C++系列 ,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新! 🌸 相关专栏推荐: C语言初阶系列 、 C语言进阶系列 、 数据结构与算法 本章我们

    2023年04月17日
    浏览(52)
  • 【C++】C++内存管理,模板

    C++中通过 new 和 delete 两个操作符实现动态内存管理 为自定义类型设计,可以在申请空间得同时初始化 使用 new 先申请空间,再调用构造 使用 delete 时先调用析构,再释放空间 operator new 和 operator delete 是系统提供的全局函数,不是运算符重载, 在使用 new 或 delete 时,底层实

    2024年02月01日
    浏览(40)
  • c++ 内存管理一:初识内存分配工具

    前言 侯捷 c++内存管理学习总结笔记。 在C++中,有几种常用的内存分配工具可以帮助进行动态内存管理。 从c++应用程序自上而下,通常会有这样的几种分配内存的方式,当然最终都是直接或间接的调用系统的API。 1 new 和 delete new 和 delete :new操作符用于在堆上分配内存,de

    2024年02月11日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包