【C++】内存管理(new与delete)

简介: 【C++】内存管理(new与delete)

前言

本篇文章我们一起来学习C++的内存管理方式,实际上C++与C语言的内存管理模式是十分相似的,他们的内存分布完全一致,C语言所学习的内存管理函数在C++中仍然适用,而new与delete的产生主观上认为是为了解决自定义类型的内存管理。


欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。

=========================================================================

GITEE相关代码:🌟fanfei_c的仓库🌟

=========================================================================


1.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);
  int* ptr2 = (int*)calloc(4, sizeof(int));
  int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
  free(ptr1);
  free(ptr3);
}
//1. 选择题:
//选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
//globalVar在哪里?____ staticGlobalVar在哪里?____
//staticVar在哪里?____ localVar在哪里?____
//num1 在哪里?____
//char2在哪里?____ * char2在哪里?___
//pChar3在哪里?____ * pChar3在哪里?____
//ptr1在哪里?____ * ptr1在哪里?____
//2. 填空题:
//sizeof(num1) = ____;
//sizeof(char2) = ____; strlen(char2) = ____;
//sizeof(pChar3) = ____; strlen(pChar3) = ____;
//sizeof(ptr1) = ____;
//3. sizeof 和 strlen 区别?

答案:

1. 选择题:

 选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)

 globalVar在哪里?__C__  staticGlobalVar在哪里?__C__

 staticVar在哪里?__C__  localVar在哪里?__A__

 num1 在哪里?__A__

 分析:

 globalVar全局变量在数据段 staticGlobalVar静态全局变量在静态区

 staticVar静态局部变量在静态区  localVar局部变量在栈区

 num1局部变量在栈区

 char2在哪里?__A__  *char2在哪里?__A__

 pChar3在哪里?__A__   *pChar3在哪里?__D__

 ptr1在哪里?__A__    *ptr1在哪里?__B__

 分析:

 char2局部变量在栈区  

 char2是一个数组,把后面常量串拷贝过来到数组中,数组在栈上,所以*char2在栈上

 pChar3局部变量在栈区   *pChar3得到的是字符串常量字符在代码段

 ptr1局部变量在栈区     *ptr1得到的是动态申请空间的数据在堆区

2. 填空题:

 sizeof(num1) = __40__;//数组大小,10个整形数据一共40字节

 sizeof(char2) = __5__;//包括\0的空间

 strlen(char2) = __4__;//不包括\0的长度

 sizeof(pChar3) = __4__;//pChar3为指针

 strlen(pChar3) = __4__;//字符串“abcd”的长度,不包括\0的长度

 sizeof(ptr1) = __4__;//ptr1是指针

全局变量和在全局定义的静态变量的区别:

  • 最主要的区别在于链接属性不同,static修饰的全局变量只在当前文件可用,而全局变量其他文件也可以使用。

说明:

  1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的,栈空间由系统分配,但可以通过函数alloca进行动态分配,不过注意,所分配空间不能通过free或delete进行释放。
  2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(了解)
  3. 堆用于程序运行时动态内存分配,堆是可以上增长的,堆只能动态分配,不能静态分配
  4. 数据段--存储全局数据和静态数据。
  5. 代码段--可执行的代码/只读常量

🔎做几道小题🔍


分析:

A.栈区主要存在局部变量和函数参数,其空间的管理由编译器自动完成,无需手动控制,堆区是自己申请的空间,在不需  要时需要手动释放

B.栈区先定义的变量放到栈底,地址高,后定义的变量放到栈顶,地址低,因此是向下生长的,堆区则相反

C.频繁的申请空间和释放空间,容易造成内存碎片,甚至内存泄漏,栈区由于是自动管理,不存在此问题

D.32位系统下,最大的访问内存空间为4G,所以不可能把所有的内存空间当做堆内存使用,故错误

答案:D



分析:

A.堆大小受限于操作系统,而栈空间一般有系统直接分配

B.频繁的申请空间和释放空间,容易造成内存碎片,甚至内存泄漏,栈区由于是自动管理,不存在此问题

C.堆无法静态分配,只能动态分配

D.栈可以通过函数alloca进行动态分配,不过注意,所分配空间不能通过free或delete进行释放

答案:C


2.C++内存管理方式

C++为了解决自定义类型的内存管理,提出了自己的内存管理方式:通过newdelete操作符进行动态内存管理。

2.1new/delete操作内置类型

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

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用

new[]和delete[],注意:匹配起来使用

2.2new/delete操作自定义类型

class A
{
public:
  A(int a = 0)
    : _a(a)
  {
    cout << "A():" << this << endl;
  }
  ~A()
  {
    cout << "~A():" << this << endl;
  }
private:
  int _a;
};
int main()
{
  A* p1 = (A*)malloc(sizeof(A));
  A* p2 = new A(1);
  free(p1);
  delete p2;
  // 内置类型是几乎是一样的
  int* p3 = (int*)malloc(sizeof(int)); // C
  int* p4 = new int;
  free(p3);
  delete p4;
  A* p5 = (A*)malloc(sizeof(A) * 10);
  A* p6 = new A[10];
  free(p5);
  delete[] p6;
  return 0;
}

new/delete 和 malloc/free最大区别:

new/delete对于【自定义类型】除了开空间,还会调用构造函数和析构函数.


3.operator new与operator delete函数

operator new与operator delete是系统提供的两个全局函数,本质上可以等价为malloc和free,他们不会调用构造函数与析构函数.


那C++为什么会存在这两个全局函数,他们的意义是什么呢?

我们知道new操作符可以干两件事:

1.开空间

2.调用构造函数


那开空间是怎么开的呢?

实际上就利用了operator new这个全局函数.


可是本来不是有malloc,为啥又单独弄一个operator new呢?

我们知道C++是面向对象的语言,而malloc如果申请失败的话返回的是0,可是面向对象的语言可不认这个0,面向对象语言对于失败的处理一般都是抛异常,也就是说operator new就是malloc的封装,只不过多实现了抛异常这个过程罢了.

那delete在底层释放空间时也是会调用operator delete,其余的细节和上面相似就不过多赘述了.

另外对于new T[n]和delete[],C++也提供了他们对应开空间的全局函数,分别为operator new[]与operator delete[],实际上这两个全局函数的内部还是operator new与operator delete,大家可以理解为换皮(仅为了区分用).


🐸总结一下🐸


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来释

放空间


4.高频面试题

👓malloc/free和new/delete的区别👓

共同点是:都是从堆上申请空间,并且需要用户手动释放。

不同的地方是:

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在释放空间前会调用析构函数完成空间中资源的清理


=========================================================================

如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容

🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎

🌟~ 点赞收藏+关注 ~🌟

=========================================================================

目录
打赏
0
0
0
0
1
分享
相关文章
玩转C++内存管理:从新手到高手的必备指南
C++中的内存管理是编写高效、可靠程序的关键所在。C++不仅继承了C语言的内存管理方式,还增加了面向对象的内存分配机制,使得内存管理既有灵活性,也更加复杂。学习内存管理不仅有助于提升程序效率,还有助于理解计算机的工作原理和资源分配策略。
C++/C的内存管理
本文主要讲解C++/C中的程序区域划分与内存管理方式。首先介绍程序区域,包括栈(存储局部变量等,向下增长)、堆(动态内存分配,向上分配)、数据段(存储静态和全局变量)及代码段(存放可执行代码)。接着探讨C++内存管理,new/delete操作符相比C语言的malloc/free更强大,支持对象构造与析构。还深入解析了new/delete的实现原理、定位new表达式以及二者与malloc/free的区别。最后附上一句鸡汤激励大家行动缓解焦虑。
【硬核】C++11并发:内存模型和原子类型
本文从C++11并发编程中的关键概念——内存模型与原子类型入手,结合详尽的代码示例,抽丝剥茧地介绍了如何实现无锁化并发的性能优化。
220 68
彻底摘明白 C++ 的动态内存分配原理
大家好,我是V哥。C++的动态内存分配允许程序在运行时请求和释放内存,主要通过`new`/`delete`(用于对象)及`malloc`/`calloc`/`realloc`/`free`(继承自C语言)实现。`new`分配并初始化对象内存,`delete`释放并调用析构函数;而`malloc`等函数仅处理裸内存,不涉及构造与析构。掌握这些可有效管理内存,避免泄漏和悬空指针问题。智能指针如`std::unique_ptr`和`std::shared_ptr`能自动管理内存,确保异常安全。关注威哥爱编程,了解更多全栈开发技巧。 先赞再看后评论,腰缠万贯财进门。
126 0
什么是内存泄漏?C++中如何检测和解决?
大家好,我是V哥。内存泄露是编程中的常见问题,可能导致程序崩溃。特别是在金三银四跳槽季,面试官常问此问题。本文将探讨内存泄露的定义、危害、检测方法及解决策略,帮助你掌握这一关键知识点。通过学习如何正确管理内存、使用智能指针和RAII原则,避免内存泄露,提升代码健壮性。同时,了解常见的内存泄露场景,如忘记释放内存、异常处理不当等,确保在面试中不被秒杀。最后,预祝大家新的一年工作顺利,涨薪多多!关注威哥爱编程,一起成为更好的程序员。
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
105 3
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
324 4
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
130 29
JVM简介—1.Java内存区域
JVM实战—2.JVM内存设置与对象分配流转
本文详细介绍了JVM内存管理的相关知识,包括:JVM内存划分原理、对象分配与流转、线上系统JVM内存设置、JVM参数优化、问题汇总。
JVM实战—2.JVM内存设置与对象分配流转
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略

热门文章

最新文章