C++ new/delete和new[ ]/delete[ ] 深入解析

 

在C语言中,用malloc/free 从堆里面动态申请出来一段内存。但对这一块申请出来的内存,往往还需要对它进行初始化 。虽然C语言提供了calloc来开辟一段初始化好(0)的内存,但面对各式各样的数据成员初始化,它同样束手无策。同时,为了保持良好的编程习惯,应该对申请出来的内存手动进行初始化。

在C++中有了new/delete, new []/delete[] ,用它们便可较方便地实现动态的内存管理。

一、new/delete, new []/delete []  初始化

int* p1=new int;       //动态分配4个字节(1个int)的空间单个数据
int* p2=new int(3);   //动态分配4个字节(1个int)的空间,并初始化为3
int* p3=new int[3];   //动态分配12个字节(3 个int)的空间
delete p1;
delete p2;
delete[] p3;

new/delete动态管理对象,new[]/delete[]动态管理对象数组

在C++中,把int 、char..等内置类型的变量也看作对象,它们也是存在构造函数和析构函数的,只是通常对它们,系统调用了默认的构造函数来初始化以及默认的析构(编译器优化)。所以new int、new int(3)看起来和普通的定义好像没什么区别。 但对于自定义类型的对象,此种方式在创建对象的同时,还会将对象初始化好;于是new/delete、new []/delete []方式管理内存相对于malloc/free的方式管理的优势就体现出来了,因为它们能保证对象一被创建出来便被初始化,出了作用域便被自动清理。

二、malloc/free和new/delete的区别

malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员)。
它们都是动态管理内存的入口。
malloc/free是C/C++标准库的函数,new/delete是C++操作符。
malloc/free需要手动计算类型大小且返回值为void*,new/delete可自动计算类型的大小,返回对应类型的指针。
malloc/free管理内存失败会返回0,new/delete等的方式管理内存失败会抛出异常。

三、new/delete的真正调用

尽管看起来new、new[] 和malloc 都能开得空间出来,并且以new 、new[]的方式好像还更有优势。但从系统层面看来,真正开出空间来的还是malloc。为什么这么说呢?

在C++ Primer书中有提到说: new/delete的表达式与标准库函数同名了,所以系统并没有重载new或delete表达式。new/delete真正的实现其实是依赖下面这几个内存管理接口的。c++中称之为“placement版”内存管理接口

void * operator new (size_t size);  
void operator delete (void* ptr,size_t size);

void * operator new [](size_t size);  
void operator delete[] (void* ptr,size_t size);

代码实现:

#include<iostream>
#include<stdlib.h>
#include<cstdio>
using namespace std;

class Test
{
	int val;
	double t;
public:
	Test(const int val):val(val){}
	Test(void)
        {
            cout<<"构造函数"<<endl;
        }
	~Test(void)
	{
		cout<<"析构函数"<<endl;
	}
	void* operator new(size_t size)
	{
		printf("申请内存:%d\n",size);
		return malloc(size);
	}
	void operator delete(void* ptr,size_t size)
	{
		printf("释放内存:%d\n",size);
		free(ptr);
	}
};

int main()
{
	Test* p1=new Test;
	delete p1;
}

delete[]实际做了这样几件事情:

1、依次调用pA指向对象数组中每个对象的析构函数,共n次

2、调用operator delete[](),它将再调用operator delete

3、底层用free执行operator delete表达式,依次释放内存

那么编译器怎么知道要释放几次?

new最后将开辟好内存用指针p返回,在它之前用4个字节来保存一个东西——对象个数,即n。这也就不难解释 为什么在delete[] 的时候,不用传给它对象个数。

delete[] 删除时,将new[] 返回的地址再往前移4个字节便可以拿到要析构的对象个数了。

注意:new type[] ,只有type显示定义析构函数时,编译器才会多开4字节来保存对象个数。所以像new int、char这样的内置类型编译器不会多开这4字节,编译器自行优化

new/delete、new[]/delete[] 要配套使用!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值