【C++初阶】C++内存管理(下)

简介: 【C++初阶】C++内存管理

3.new和delete不匹配问题(了解)

案例:不匹配现象

  //1.
  int* ptr1 = new int;
  delete[] ptr1;
  //2.
  int* ptr2 = new int[10];
  delete ptr2;
  //3.
  int* ptr3 = new int;
  free(ptr3);

不匹配后果:未定义,由于环境(linux还是windows或者不同编译器)不同,结果不同,不要尝试不匹配

ps:这个问题不是内存泄漏问题(内存泄漏是不会报错的,类似一种慢性病,报错类似一种急性病)

4.new的底层机制(了解)

new的底层机制其实是调用operator new函数申请空间 + 调用构造函数初始化


而operator new申请空间的底层实现也是调用malloc, 所以new的效率并没有比malloc高


封装malloc,申请内存失败,抛异常


封装malloc只是为了符合面向对象处理出现错误的处理方式—抛异常


2a08e5a19ac200ddbdd7fd262b663411.png

我们其实可以手动调用operator new函数

image-20221105190435366


0036f227c64925692b307bb69e34c053.png


ps:operator new函数的使用方式和malloc一样,唯一不同的是operator new开空间失败不会返回nullptr,而是抛异常.

给大家看一下调用new的时候的反汇编:

内置类型

int main()
{
  int* a = new int;
  return 0;
}

30547c2cd5893a075acc985e9ca3183f.png

这个call调用的是operator new函数

  • 自定义类型
struct ListNode
{
  int _val;
  ListNode* _next;
  ListNode(int val = 0)
    :_val(val)
    ,_next(nullptr)
  {}
};
int main()
{
  //创建链表
  ListNode* n1 = new ListNode(1);
  return 0;
}

1025ea8c28aaa9359f73c9c23d8419f9.png

第一个call是调用operator new函数


第二个call是调用构造函数


同理就有operator new[]函数,调用多次operator new


还有operator delete和operator delete[]函数


ps:我们知道new的底层机制,但是我们没有必要使用operator new去实际编程.


5.定位new表达式(了解)

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

构造函数有点不一样,在我们之前学的都不能显式调用,但是定位new表达式就可以完成显式调用

ps:析构函数可以显式调用(下图证明)

d6e31c59828cb6b13f66258e67958403.png

class A
{
public:
  A(int a = 10)
    :_a(a)
  {
    cout << "构造函数" << endl;
  }
  ~A()
  {
    cout << "析构函数" << endl;
  }
private:
  int _a;
};
int main()
{
  A* ptr1 = (A*)malloc(sizeof(A));
  if (ptr1 == nullptr)
  {
    perror("malloc fail");
    exit(-1);
  }
  //定位New--- 对ptr1指向的这块空间,显示调用构造函数初始化
  new(ptr1)A(1);
  //ps:析构函数可以显式调用
  ptr1->~A();
  free(ptr1);
  //上面两行相当于delete ptr1;
  //上节课讲过delete等同于 调用析构函数+operator delete(失败抛异常)
  return 0;
}

定位new案例:


我们听说过内存池还有池化技术,那我百度了一下,我就给大家讲一下我的理解:


举一个例子:


山上有好多和尚,他们每天需要来山脚下挑已经过滤好的自来水喝,


但每一次都要排老长老长的队,于是各个和尚都在自己家里建水池蓄水,可以避免每天排队,提高效率


于此同时也产生一个问题:蓄水池的水需要一个过滤装置定时过滤杂质后才能饮用


上述的山脚下的自来水就类似new/malloc,挑山脚下的别人已经过滤好的纯净水就是调用new/malloc开辟空间并且开好的空间是已经初始化好的,


于是和尚建蓄水池蓄水就是建内存池,提高效率


内存池的水需要定时过滤就类似定位new,对内存池的空间进行初始化


三.面试题

1.new/delete和malloc/free的区别(理解)

image.png

最大的区别是new/delete对于自定义类型能够自动调用构造函数和析构函数

2.内存泄漏

ps:内存泄漏是指针丢了,而不是内存丢了(内存一直都在)—–-指针丢了就是找不到这块空间了


(想想永不关闭的程序,比如后台服务器就知道危害了)


内存泄漏指由于疏忽或者错误造成程序未能释放已经不再使用的内存的情况


并不是指物理上的消失,而是失去了对这段内存的控制,从而造成了内存的浪费.


目录
相关文章
|
27天前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
42 3
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
81 4
|
2月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
146 21
|
2月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
2月前
|
存储 C语言 C++
【C++打怪之路Lv6】-- 内存管理
【C++打怪之路Lv6】-- 内存管理
44 0
【C++打怪之路Lv6】-- 内存管理
|
2月前
|
存储 C语言 C++
【C/C++内存管理】——我与C++的不解之缘(六)
【C/C++内存管理】——我与C++的不解之缘(六)
|
2月前
|
程序员 C语言 C++
C++入门5——C/C++动态内存管理(new与delete)
C++入门5——C/C++动态内存管理(new与delete)
76 1
|
2月前
|
C++
C/C++内存管理(下)
C/C++内存管理(下)
50 0
|
2月前
|
存储 Linux C语言
C/C++内存管理(上)
C/C++内存管理(上)
40 0
|
2月前
|
Linux C++
Linux c/c++文件虚拟内存映射
这篇文章介绍了在Linux环境下,如何使用虚拟内存映射技术来提高文件读写的速度,并通过C/C++代码示例展示了文件映射的整个流程。
58 0