C++——new,delete,与placement new。

内存管理是C++中很令人头疼的问题,巧妙使用可以获得更好的性能,否则则是一遍一遍的检查内存泄漏的问题。但内存管理在C++中无处不在,内存泄漏几乎在每个C++程序中都会发生,不像Java等其他高级语言的内存管理是自动的。
之前写了一篇关于C语言动态内存管理函数的博客 C语言——动态内存管理,现在再来谈谈关于内存的知识点和C++中的内存管理方法。

C++内存基础知识

C++将持续的数据和代码等分别存储在对应的区域。
用于存储局部变量、函数参数、返回值等。用于存储运行时动态内存分配。堆和栈相向而生。
内存映射段是高效的I/O映射方式,装载共享的动态内存库,也可作为共享内存,用于进程间通信。
静态区又叫数据段,用于存储全局变量和静态变量。
常量区和代码区顾名思义。
在这里插入图片描述

new和delete

C++新增了类的概念。C语言调用malloc后只申请空间而不初始化,free只释放空间。而new既申请内存,又调用该类型的构造函数。delete则是既释放空间,又调用析构函数。

new和malloc对于内置类型的变量来说没什么区别,但对于自定义类型的对象,此种方式在创建对象的同时,还会将对象初始化;于是new/delete、new []/delete []方式管理内存相对于malloc/free的方式管理的优势就体现出来了,因为它们能保证对象一被创建出来便被初始化,出了作用域便被自动清理。

用法

int main()
{
	int* p1 = new int;
	int* p2 = new int(10);
	int* p3 = new int[10];
	int* p4 = new int[10]{ 1,2,3,4,5 };

	delete p1;
	delete p2;
	delete[] p3;
	delete[] p4;
	return 0;
}

new[]和delete[]

string* pStr = new string[10];
delete[] pStr;

在C++中申请一个数组需要用到new[]表达式,对应地用delete[]销毁对应的数组空间。且delete的[]不能省略。
上面代码:先调用string的构造函数建立10个对象存在堆上一段连续的空间,然后在栈区上定义一个string类型的指针指向这段空间的起始地址。delete则是对10个对象分别调用他们的析构函数,然后释放掉为对象开辟的空间。
new/delete,new[]/delete[]要分别配对使用。如果上面代码中delete没有[],那会导致程序报错,至于为什么报错,下面有说。

operator new()和operator delete()

在这里插入图片描述
转到反汇编的代码可以看到,new和delete分别调用了operator new函数和operator delete函数。没错,这样的形式是函数。原型为:

void *operator new(size_t);       //allocate an object
void *operator delete(void *);    //free an object

void *operator new[](size_t);     //allocate an array
void *operator delete[](void *);  //free an array

这不是new和delete的重载,但是至于为什么这么命名我也不知道。其底层实质还是调用malloc和free,但是加上抛异常的操作,malloc申请失败是返回空指针,但是operator new调用失败是抛异常。
在这里插入图片描述
可以在类中对operator new()和operator delete()函数进行重载,执行自己想要的功能以提高效率。

	void* operator new(size_t size)
	{
		class* p = (class*)malloc(size);
		cout << "override operator new()" << endl;
		return p;
	}

	void operator delete(void* p)
	{
		free(p);
		cout << "override operator delete()" << endl;
	}
test* pTest = new test[10];

且定义一个指针用new[]申请一段连续内存,系统返回的指针地址比调用operator new()函数的形参p相比增加了四个字节,其实是因为编译器用相差的这4个字节用来保存一个东西——对象个数。因此我们在调用delete[]的时候不用指明个数,编译器会从这个指针的前四个字节处找,然后从后面的内存起始位置开始释放内存和析构对象。
在这里插入图片描述

malloc/free new/delete new[]/delete[] 配套使用

综上所述,我们应该配套使用这些函数和操作符。

情况一

在这里插入图片描述

情况二

在这里插入图片描述

总结malloc/free和new/delete的区别

  1. 前者是函数,malloc不会初始化,free只释放存储对象的内存;后者是操作符,分别会调用构造函数和析构函数。
  2. malloc需要传入要申请的空间大小,返回类型是void*,需要强制转换;后者只需要传入类型名,个数可选,返回类型是申请的类型。
  3. malloc申请失败返回NULL,new失败会抛出异常。

定位new(replacement new)

在某些特殊情况下,可能需要在已分配的特定内存处初始化对象,这就是所谓的“定位放置new”(placement new)操作。
placement new是重载operator new的一个标准、全局的重载。它不能够被用户重载(不像普通版本的operator new 和 operator delete)。
定位放置new操作的语法形式不同于普通的new操作。

// 这句是正常操作
test* pTest = new test;
//这句是先有一块堆内存,然后再使用定位new。
test* pPlacementTest = (test*)malloc(sizeof(test));
new(pPlacementTest )test;
// 形式如:new + (class*指针) + class()类(的构造函数)

int* pInt = new int;
int* pPlacementInt = (int*)malloc(sizeof(int));
new(pPlacementInt )int;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值