mallloc/free和new/delete的区别与联系

        首先我们来回顾一下在C语言中有哪些可以用于动态内存开辟的函数:

注意:这三个函数都是在堆上开辟的内存,需要用户自己来管理,所以一定要和free()函数配对使用,否则会造成内存泄漏。

动态内存开辟常见错误:

1、对NULL指针进行解引用操作(tip:开辟完先检查是否开辟成功再使用)

2、对分配的内存进行操作时越界(tip:开辟内存时,开辟足够的空间)

3、释放非动态开辟的内存(tip:开辟时用哪个指针接收的就free掉哪个指针)

4、忘记释放(tip:写开辟内存函数和free()函数配对使用)

5、释放一块动态分配的内存的一部分(tip:操作时用一个临时的指针代替内存的地址,避免改变接收内存时的指针的指向)

6、一块动态内存被释放后被继续使用(tip:将一块空间释放掉后,将指向这块空间的指针赋成NULL)


现在来看一下new/delete的用法:

在C++ 中一般通过new和delete运算符进行动态内存管理。new用于开辟内存,delete用于释放内存。

new的作用是:1、调用operator new 分配空间   2、调用构造函数初始化对象

delete的作用:1、调用析构函数清理对象  2、调用 operator new释放对象

new[ ]的作用:1、调用operator new分配空间   2、调用N次析构函数分别初始化每个对象

delete[ ]的作用:1、调用N次析构函数清理对象  2、调用operator delete 释放空间

简单使用:

#include <iostream>
using namespace std;

int main()
{
	int* p1 = new int;		//动态分配了4个字节,但是并没有初始化
	int* p2 = new int(2);	//动态分配了4个字节并将其初始化为2
	int* p3 = new int[3];	//动态分配了3个整型的空间,即12个字节的空间

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

上边的用法很简单,为内置类型开辟空间时并不需要调用构造函数,但是在为自定义类型的变量(对象)开辟空间的时候一定会调用构造函数,在结束的时候还会调用析构函数。举个例子:

#include <iostream>
using namespace std;

class Array
{
public:
	Array(size_t size = 10)//构造函数
		:_size(size)//_size被初始化为10
		, _a(0)
	{
		cout << "Array(size_t size)" << endl;
		if (_size > 0)//
		{
			_a = new int[size];//开辟10个整型大小的内存
		}
	}
	~Array()//析构函数
	{
		cout << "~Array()" << endl;
		if (_a)
		{
			delete[] _a;
			_a = 0;
			_size = 0;
		}
	}
private:
	int *_a;
	size_t _size;
};
void Test()
{
	Array* p1 = (Array*)malloc(sizeof (Array));
	Array* p2 = new Array;//调用一次构造函数
	Array* p3 = new Array[10];//调用10次构造函数

	free(p1);
	delete p2;//调用一次析构函数
	delete[] p3;//调用十次析构函数	
}
int main()
{
	Test();
	return 0;
}

运行结果为:

正好是分别调用了11次构造函数和析构函数

注意:对于new type [ ]  只有显示定义析构函数的时候会多开辟4个字节来存储对象个数


定位new表达式:

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

使用格式有两种:

1、new  (place_address) type

2、new  (place_address) type (初始化列表)

malloc/free和new/delete的异同:

共同点:都是从对堆上来开辟空间,用户需要自己管理。

不同点:

       还需要再次强调一下,当使用new[] 一次性为多个对象开辟空间的时候,会在分配的空间前多开辟4个字节大小的空间,用于存储此次为多少个对象开辟了空间。方便后边调用对应次数的析构函数。如果没有这4个字节的空间存放个数,在这块空间被释放的时候就不知道该调用多少次析构函数。

       如果多调了几次,不用说,肯定会出问题,如果少调了的话,就有可能会出现内存泄漏。可能有读者会这么认为,开辟了这块空间,虽然没有调用对应次数的析构函数,但是,我把这块空间已经释放了,何来的内存泄漏?这是忽略了一种情况,那就是类对象的成员指向了一块自己申请的空间。比如说类对象的其中一个成员就是一个动态数组,其实这个成员只是指向了这个动态数组空间的起始地址,也就是一个指针,在没有调用析构函数的情况下,将类对象的空间释放了,其实释放的只是存放那个动态数组的首地址的那块空间,而没有把 整个数组的空间释放掉,这就造成了内存泄漏。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值