首页 > 系统相关 >C++:内存管理

C++:内存管理

时间:2024-08-13 09:23:45浏览次数:13  
标签:malloc 管理 int C++ 空间 内存 operator new delete

C++内存管理的概念

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

new/delete       

                new/delete操作内置类型:

int main()
{
	int* p1 = (int*)malloc(sizeof(int));

	//动态申请一个int对象
	int* p2 = new int;

	//动态申请一个int对象并初始化为1
	int* p3 = new int(1);

	//动态申请一个长度为4的数组并初始化为0
	int* p4 = new int[4] {0};

	free(p1);
	delete p2;
	delete p3;
	delete [] p4;

	return 0;
}

                以下是关于代码的解释:

                int* p1 = (int*)malloc(sizeof(int)):因为C++是C的延申,所以C++兼容C语言,在C++里也可以使用C语言的代码,malloc从堆中分配了一个int类型的空间,这个大家都熟悉.

                int* p2 = new int;这里使用C++新引入的关键字new,new跟malloc操作类似,都是向申请了一个int类型的空间

                int* p3 = new int(1);使用new向堆申请了一个int类型的空间,但不同的是在类型后面跟了(1),通过调试可以看到在申请完空间的同时将空间内的数据初始化为1。

                int* p4 = new int[4] {0};使用new申请了一个长度为4的int数组,并将数组中的所有元素初始化为0。

                free(p1);释放使用malloc分配的内存。

                delete p2; delete同样也是C++新引入的关键字,用于释放动态分配内存的运算符,后面代码跟这段类似就不展开了。

     

                new/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));
	cout <<"p1:"<< p1 << endl;

	A* p2 = new A(1);
	cout << "p2:" << p2 << endl;
	free(p1);
	delete p2;

	return 0;
}

	

        上图代码创建了两个对象指针,唯一区别的是p1指向的空间是通过malloc分配来的。p2指向的空间是通过new分配来的。

        可以很明显的看出在通过new在堆上创建对象,会调用构造函数初始化对象,以及delete释放空间的时候会调用析构函数。

        

        那么当通过new申请5个对象数组时候,通过上图代码会发现编译器为给每个对象都进行默认构造。如果将默认构造的参数删除变成普通的构造函数,那么再次运行程序编译则会报错。除非给每个对象都传入参数。

        小结:    

         new/delete 和 malloc/free最大区别是 new/delete对于 自定义类型 除了开空间 还会调用构造函数和析构函数。

operator new与operator delete函数:

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

operator new源码:

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

   

operator delete源码:

void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}

free源码:

#define free(p) _free_dbg(p, _NORMAL_BLOCK)

        通过上图operator new源码可以看见在operator new源码里同样调用了malloc,但是operator new会在使用完malloc后进行判断是否申请内存成功,如果不成功会抛出异常(显示异常状态) 。

        operator delete与free同样都执行_free_dbg这段代码,但operator delete会做更多的处理,比如当重复释放同一块空间,operator delete则会抛出异常,让程序员更清楚的知道问题出现在哪。

        上图代码写了一个try  catch用于捕捉异常,以及do while的死循环,p1每次都向堆申请1MB的空间。通过任务管理器可以看到此时vs的运行窗口直接占用了2G左右的内存就不动了,说明此时堆上已经没有空间申请,当程序继续运行也没有发生而是捕捉到了编译器抛出的异常,输出bad allocation(糟糕的分配),提示程序员问题的出处。

       小结:

        通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果 malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施 就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。   

new和delete的实现原理                 

                实现内置类型:

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

                实现自定义类型:

        上图通过new从堆上申请了一个A类的对象空间,通过p1指针进行接受,接着释放p1。下图将通过调试的反汇编可以很清晰明了的观察到new和delete是如何实现创建自定义类型的对象。

        可以看到当使用new创建对象的时候并不是直接申请对象,而是先调用operator new从堆上申请一块空间,接着调用构造函数 A(int a),对对象进行初始化。

        delete在一开始执行的时候会调用一个函数,这个函数封装了A类的析构函数以及operator delete。可以看到delete会先调用析构函数,将对象内的成员进行析构,再调用operator delete释放堆上对象占用的空间。

        

        从上图例子并不能很好的看出new/delete的区别,接下来小编将实现一个栈的数据结构,让读者更好的理解为什么C++中会使用new/delete,而不是继续沿用malloc/free

        上图实现了Stack类的数据结构,Stack类中的成员变量_arr是一个指针,在构造函数中向堆申请一块空间。在主函数里用new向堆中申请一块空间存放一个Stack对象,用st指针进行接收。new会先进行开空间,接着调用构造函数又给成员变量_arr申请了一块空间。当对st进行释放的时候,delete会先调用析构函数,释放_arr所申请的空间,再释放Stack对象的空间。

   

总结 new/delete与malloc/free的区别:

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

标签:malloc,管理,int,C++,空间,内存,operator,new,delete
From: https://blog.csdn.net/2301_80894970/article/details/141138741

相关文章

  • C++:类与对象(下)
    再探构造函数        构造函数体赋值与初始化列表其实之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表,C++规定初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟......
  • C++:类与对象(中)
    类的默认成员函数:        在C++中,如果你没有显式地定义某些特定的成员函数(如构造函数、析构函数、拷贝构造函数、拷贝赋值运算符和移动构造函数),那么编译器会自动生成这些函数。这些由编译器自动生成的函数被称为默认成员函数。        构造函数   ......
  • ntdsutil.exe 是一个用于管理和维护 Windows Server 中的 Active Directory 数据库的
     ntdsutil.exe是一个用于管理和维护WindowsServer中的ActiveDirectory数据库的命令行工具。它允许管理员执行多种任务,包括: 备份和还原ActiveDirectory数据库:你可以使用ntdsutil来创建数据库的备份、还原数据库以及检查和修复数据库的完整性。维护和修复Act......
  • 从自建到云原生:数据管理的未来与变革
    前言最近,我看完腾讯云社区发布的纪录片《中国数据库前世今生》,其中有段话让我忍俊不禁。纪录片提到,云数据库刚刚兴起时,最大的挑战并不是来自竞争对手,而是来自那些选择在云服务器上自建数据库的用户。关于这部纪录片,我有许多深刻的感想。从国产数据库的探索历程,到我个人在数据库......
  • C语言和C++中的动态内存管理------malloc和free的区别
    引言:动态内存管理:需要根据具体情况来设定需要的内存大小,同时可能需要大于1Mbyte的连续空间。此时我们无法使用静态数组。原因是因为静态数据的开辟是在栈空间,其次栈空间的大小在连续分配时不能超过1Mbyte,因此引入了动态内存管理。C语言C语言中动态内存管理的有四个函数:mal......
  • SecureCoding in C and C++(二)
    经过上期的环境搭建过后,我们将正式的学习C++系列,首先要学习的是C++的一些常用的变量从编译和连接学起似乎也是不错的选择。个人总结的一句话:编译其实就是对预处理语句进行处理后,然后对语句进行处理。对预处理语句,例如:#include之类的处理方式其实就是将文件内容复制到对应......
  • C ++ 也可以搭建Web?高性能的 C++ Web 开发框架 CPPCMS + MySQL 实现快速入门案例
    什么是CPPCMS?CppCMS是一个高性能的C++Web开发框架,专为构建快速、动态的网页应用而设计,特别适合高并发和低延迟的场景。其设计理念类似于Python的Django或RubyonRails,但针对C++提供了更细粒度的控制和更高效的性能。主要特点和优点1.高性能与并发处理​Cp......
  • 快速认识JVM,深入掌握类加载器、JVM内存空间、JVM垃圾回收机制和双亲委派机制。
    什么是JVM    JVM(JavaVirtualMchine)java虚拟机,主要作用就是将Java字节码文件解释为能被各种操作系统理解的机器码。JVM的三大功能    1.解释和运行:将字节码文件翻译为能被各种操作系统理解的机器码。    2.内存分配:给对象及其方法分配内存,管理......
  • Linux进程和计划任务管理
    目录一、进程基本概念1.进程2.程序和进程的关系 二、查看进程信息1.ps命令1.1 psaux命令1.2ps-elf命令 2.top命令 3.pgrep命令 4.jobs命令 三、查看进程树 四、进程的启动方式1.手动启动2.调度启动五、终止进程的运行1.Ctrl+C组合键2.kill......
  • C++类和对象(类的定义)
    目录一·类的定义1.1类的定义格式1.2访问限定符(public、private、protected)1.3类域一·类的定义1.1类的定义格式定义类的关键字是class,类定义结束时,后面的分号不能省略。类体中的内容称为类的成员:①类中的变量称为类的属性或成员变量;②类中的函数称为类的方......