【C++基础(九)】C++内存管理--new一个对象出来

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++

🔝🔝


C++内存管理

  • [1. 前言](#1. 前言 "#1__15")
  • [2. new](#2. new "#2__new_37")
    • [2.1 new的使用方法](#2.1 new的使用方法 "#21_new_38")
    • [2.2 new的特性(对比malloc)](#2.2 new的特性(对比malloc) "#22_newmalloc_80")
  • [3. delete](#3. delete "#3_delete_92")
    • [3.1 delete的使用方法](#3.1 delete的使用方法 "#31_delete_96")
    • [3.2 delete的特性(对比free)](#3.2 delete的特性(对比free) "#32_deletefree_121")
  • [4. 全局函数operator new](#4. 全局函数operator new "#4_operator_new_140")
  • [5. 全局函数operator delete](#5. 全局函数operator delete "#5_operator_delete_182")
  • [6. new的实现原理](#6. new的实现原理 "#6_new_222")
  • [7. delete的实现原理](#7. delete的实现原理 "#7_delete_240")
  • [8. 总结以及拓展](#8. 总结以及拓展 "#8__259")

1. 前言

在C语言中,有四个内存管理函数:
malloc,calloc,realloc和free

但是它们的使用十分的不方便:

cpp 复制代码
int* p=(int*)malloc(sizeof(int)*n);

代码量很大,并且有一个新的问题:

malloc函数不会初始化变量
当变量是自定义类型的时候
C语言的内存管理函数无法
自动调用变量的构造/析构函数!

于是C++祖师爷发话了:
C++要自己搞一个内存管理!


2. new

2.1 new的使用方法

new的使用方法:

  1. 开辟多个空间
cpp 复制代码
int* p = new int[100];

这段代码可以这样理解:


  1. 开辟一个空间并初始化
cpp 复制代码
class A
{
public:
 A(int a = 0)
 : _a(a)
 {}
private:
 int _a;
};

A* p = new A(10);

使用小括号()
这段代码初始化了一个对象成10
并且将地址赋值给指针变量p


  1. 开辟多个空间并初始化
cpp 复制代码
A* p = new A[5]{1,2,3};

这段代码可以这样理解:


2.2 new的特性(对比malloc)

new的特性:

  • 对于内置类型来说,new和malloc
    并没有太大的区别
  • 对于自定义类型来说,new会调用
    自定义类型的构造函数,而malloc不会
  • new可以初始化变量的内容

3. delete

delete对比C语言中的free
是用来使用同台开辟的空间的/1

3.1 delete的使用方法

delete的使用:

  1. 直接使用delete
cpp 复制代码
int* p = new int(10);
//使用指针p
delete p;

当new堆区空间时只开辟了一份空间
释放空间时直接使用delete即可

  1. 使用delete[]
cpp 复制代码
int* p = new int[10]{1,2,3,4};
//使用指针p
delete[] p;

当new使用方括号\[\]开辟多个空间时
delete也要对应的加上\[\]来释放空间
否则会出错


3.2 delete的特性(对比free)

delete特性:

  • 对于内置类型,delete和free没有区别
  • 对于自定义类型,delete会调用
    自定义类型的析构函数,而free不会
  • delete面对不同的情况需要加上
    然而free不用考虑

对于自定义类型来说
有可能类中有指针指向一块堆区
如果不调用析构函数释放这块空间
直接用free释放掉对象的空间
那么这块空间就会内存泄漏!


4. 全局函数operator new

不同于C语言的malloc和free函数
new和delete是两个操作符
那new是怎样开辟空间的呢?

new在底层调用了operator new

注:
operator new是全局函数
不是运算符重载

库中的operator new函数:

cpp 复制代码
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)
	if (_callnewh(size) == 0)
	{
	    // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
	    static const std::bad_alloc nomem;
	    _RAISE(nomem);
	}
return (p);
}

可以发现,new的底层实际上是
使用了malloc来实现开辟空间

开辟空间成功,会返回指向此空间的指针
开辟空间失败,会抛异常

抛异常不是本节课的重点
它是C++一个全新的知识
在后面的章节会详细介绍
一般情况下,new申请空间都不会失败!


5. 全局函数operator delete

和new对应的delete的底层
也是调用了operator delete来
释放堆区开辟的空间

库中的operator delete函数:

cpp 复制代码
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
void operator delete(void *pUserData)
{
     _CrtMemBlockHeader * pHead;
     RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
     if (pUserData == NULL)
         return;
     _mlock(_HEAP_LOCK);
     __TRY
         pHead = pHdr(pUserData);
         _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
         _free_dbg( pUserData, pHead->nBlockUse );
     __FINALLY
         _munlock(_HEAP_LOCK);
     __END_TRY_FINALLY
     return;
}

看不懂没关系,只需要抓住重点:
delete里面调用了:
_free_dbg(p, _NORMAL_BLOCK)
然而此函数正是free函数定义的宏替换!

说明delete的底层实现实际上
是调用了C语言中的free函数

delete是使用free来释放空间的


6. new的实现原理

对于内置类型来说,new和
malloc的实现是一样的

对于自定义类型来说

  • new的原理步骤
  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数
    完成对象的构造
  • new T[N]的原理步骤
  1. 调用operator new\[\]函数
    完成N个对象空间的申请
  2. 在申请的空间上执行N次构造函数

7. delete的实现原理

对于内置类型来说,delete
和free的实现是一样的

对于自定义类型来说

  • delete的原理步骤
  1. 在空间上执行析构函数
    完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间
  • delete[]的原理步骤
  1. 在释放的对象空间上执行N次析构函数
    完成N个对象中资源的清理
  2. 调用operator delete\[\]释放空间

8. 总结以及拓展

此章总结完,就可以去new一个对象了
并且C++和C语言中的内存管理区别
是面试中的常考点,和指针与引用的区别
俗称"面试山上的看门二虎"

下面就来总结一下:

  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++模板初阶讲解 🔍

相关推荐
2035去旅行5 小时前
bootcmd 详细讲解
linux·嵌入式·arm·soc
陈希1236 小时前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
女神下凡7 小时前
芯参谋(95):嵌入式文件系统_开发指南
linux·服务器·arm开发·驱动开发·设计规范
且从容.10 小时前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道11 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.14 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落15 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨15 小时前
WSL2的安装与使用
linux·wsl
微小的鱼15 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng16 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器