c++动态内存管理

本文介绍了C++中的new/delete与new[]/delete[]操作符的使用方法及其与C语言中malloc/free的区别。通过示例代码展示了如何正确使用这些操作符进行内存分配与释放,并解释了它们在对象构造和析构中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

new / delete / new[ ] / delete[ ]

与C语言不通,C++更多使用new和delete进行内存管理

int *p=new int;//开辟1个整型大小的空间,并由p指向它。

int *p1=new int(3);//开辟1个整型大小的空间并初始化为3,由p1指向它。

int *p2=new int[2];//开辟2个整型大小的空间,并由p2指向它。

delete p;
delete p1;   //释放p,p1,p2指向的空间。
delete[] p2;

能够发现,new/delete对应单个变量的内存开辟,new[ ]/delete[ ]对应数组的开辟。使用时一定要记得对应,不然可能会出现内存泄漏甚至崩溃的问题。


C/C++内存管理

这里写图片描述

  • 栈又称堆栈,非静态局部变量,函数参数,返回值等等都存在栈上,栈是向下增长的。
  • 内存映射是高效的i/o映射方式,用于装载一个动态的动态内存库,用户可以使用系统接口创建共享内存,做进程间通信。
  • 堆用于程序执行时的动态内存分配,堆是向上增长的。
  • 数据段:存储全局数据和静态变量。
  • 代码段:可执行的代码/只读常量。

我们发现,C++是兼容C的,在C++程序里使用malloc/ free一样可以开辟空间,那为什么还要使用new/delete呢?

new/delete 和 malloc/free 的区别和联系

  • 他们都是用于动态内存管理的接口
  • malloc/free是C/C++标准库函数,而new/delete是C/C++的操作符
  • new/delete在开辟/释放空间的同时,会对应调用构造函数和析构函数。而malloc/free不会
  • 用malloc开辟空间时,需要自己计算开辟的大小,且默认指针类型是void*,而new不用计算加调整指针类型,编译器会自己搞定。
  • 使用malloc开辟内存,倘若失败,会返回0,而new失败会抛异常,更早的被发现。

上述的区别与联系中,需要重点了解的是第三条,看看下面的代码:

#include<iostream>
#include<stdlib.h>


using namespace std;

class Array
{
public:
	Array(size_t size = 10)
		: _size(size)
		, _a(0)
	{
		cout << "Array(size_t size)" << endl;
		if (_size > 0)
		{
			_a = new int[size];
		}
	}

	~Array()
	{
		cout << "~Array()" << endl;
		if (_a)
		{
			delete[] _a;
			_a = 0;
			_size = 0;
		}
	}
private:
	int*_a;
	size_t _size;
};


int main()
{
	Array* p1 = (Array*)malloc(sizeof(Array));
	Array* p2 = new Array;
	Array* p3 = new Array(20);
	Array* p4 = new Array[10];
	free(p1);
	delete p2;
	delete p3;
	delete[] p4;
	system("pause");
}

这里写图片描述

可以看出new在创建对象的同时已经调用了析构函数进行初始化。


operator new和operator delete

这里写图片描述

  1. operator new/operator delete operator new[]/operator delete[] 和 malloc/free用法一样。
  2. 他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。
  3. 实际operator new和operator delete只是malloc和free的一层封装。

new做了两件事

  1. 调用operator new分配空间。
  2. 调用构造函数初始化对象。
    delete也做了两件事
  3. 调用析构函数清理对象
  4. 调用operator delete释放空间
    new[N]
  5. 调用operator new分配空间。
  6. 调用N次构造函数分别初始化每个对象。
    delete[ ]
  7. 调用N次析构函数清理对象。(思考这里怎么N是怎么来的?)
  8. 调用operator delete释放空间。

这里就有一个问题了:在使用delete [ ]释放空间的时候,编译器怎么知道该调用多少次析构函数呢?
这里写图片描述

原来在用new[ ] 开辟多个对象的空间时,系统在该开辟内存大小前多分配了4个字节的内存,用来存对象的个数,这样在delete[ ]时,就能取到对象的个数了。

但是在C++编译器中,在如下情况下就不会开辟:

  • 开辟的对象是系统的内置类型
  • 开辟的对象数量是1个
  • 在释放内存是不会调用析构函数
  • 没有自定义析构函数

以下情况均有定义析构函数:
new 和delete[ ]:
new开辟了1个对象的空间,不会多分配4个字节存对象个数,而delete[ ] 会误认为开辟了多个对象,会去访问前面的那4个字节,这就属于非法访问,系统会报错

new[ ]和 delete
new[ ]开辟了多个对象的空间,而delete误认为只开辟了1个对象的空间,所以,在free时首地址出现错误,无法正常释放空间。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值