new和delete的内存管理


在C语言中,在 堆栈上申请空间 1的方法就是调用 malloc()函数,释放空间就调用 free()函数,而到了C++几乎就看不到他们的身影,为什么C++就不推荐使用这两个函数来申请内存空间了呢,下面我们来详细学习一下在C++里面申请空间的方式。

一,new/delete 和 malloc()/free()

在C/C++中malloc()new的作用是一样的,都是在堆区申请到一块内存。free()delete一样,讲申请到的内存释放掉。但是两者的表现形式和实现方法又有所不同。下面我们重点学习一下。

newdelete是C++里面的关键字,它是被C++封装好的,因为C++是在C语言改进后定制的,设计C++的牛人固然要对C语言之前的不足加以改进,而new和delete的就是专门为C++改进的成果。

malloc()free()是C里面的函数,因为C语言是面向过程的,所以对内存的申请,只要调用该函数即可,无需增加其他的东西多此一举,而C++是面向对象的,malloc()free()已经不太能满足需要了,所以设计出了对应的newdelete来满足释放对象申请的内存的需要。

二,new和delete的实现原理

前文简绍了newdelete是在malloc()free()改进的基础上实现的,那么具体是如何实现的呢,下面来详细分析一下。
首先看下面这段代码:

int main()
{
	int* p = new int;
	delete p;
	return 0;
}

在这里插入图片描述
从反汇编可以看到,newdelete的使用,他们调用了operator new()operator delete()函数来进行底层操作,我们可以去查阅资料了解这两个函数的功能,下面是两个函数的源代码:

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
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: 该函数最终是通过free来释放空间的
*/
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;
}

void operator new() void operator delete()这两个函数是系统函数,他们的功能实现是借助了malloc()free(),只不过是在实现的过程中进行了其他功能的添加。比如:释放对象的内存时,会调用他的析构函数。所以,newdelete的本质调用还是malloc()free()的使用

三,new,delete和malloc(),free()的使用场景

这里建议是:

  1. new和delete配套使用,malloc()和free()配套使用。
  2. 一般内置类型new,delete和malloc(),free()可以混搭,因为内置类型没有析构函数,但都建议配套使用,不要混搭。
class A
{
	int _a;
	int* _ptr;

public:
	A()
	{
		cout << "A()" << endl;
		_a = 0;
		_ptr = new int;
	}
	~A()
	{
		cout << "~A()" << endl;
		free(_ptr);
	}
};
int main()
{
	A* pa = new A;
	A* pb = new A;
	free(pa);
	delete pb;
	return 0;
}

在这里插入图片描述
如图证明了delete是会调用对象的析构函数的,而free()不会,

原因:

  1. 容易造成内存泄露
  2. 会有无法预料的错误发生

为什么要搭配使用,其实是由他们各自的实现原理和编译器的执行决定的。比如说下面情况就不行:
内存泄漏

class A 
{
	int _a;
	int* _ptr;

public:
	A()
	{
		_a = 0;
		_ptr = new int;
	}
	~A()
	{
		free(_ptr);
	}
};
int main()
{
	A* pa = new A;
	free(pa);
	return 0;
}

这里_ptr指向在堆区的内存未释放。因为free()函数不会去调用对象的析构函数,那么在对象里面申请的空间未释放就造成内存泄漏。

无法预料的错误

class A 
{
	int _a;
	int* _ptr;

public:
	A()
	{
		_a = 0;
		_ptr = new int;
	}
	~A()
	{
		free(_ptr);
	}
};
int main()
{
	A* pa = new A[10];
	free(pa); // 有可能释放的地址不对,而导致错误
	// delete[] pa; // 正确写法
	return 0;
}

这个例子在不同平台有不同结果,在vs2013就会报错,而vs2022却不会了。一般报错都是释放的地址错误。

四,new,delete和malloc(),free()的区别

他们的区别可以从三个方面来理解

定义上:

  • new,delete是关键字,malloc()和free()是函数

用法上:

  • new发生错误报异常,malloc()发生错误返回NULL
  • new申请内存空间不需要传大小,malloc()要传大小,还要进行类型转换
  • new申请的内存空间可以初始化(用定位new),malloc()的不行

原理上:

  • new,delete申请内存时会调用对象的构造和析构函数,malloc()和free()的不会

  1. c/c++内存分配管理 ↩︎

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值