CD31.【C++ Dev】类和对象(21) 内存管理(中)

目录

1.new和delete的底层实现

测试代码分析

观察现象

单步调试,进入new的细节部分

但能说明new等价为operator new吗?

单步调试,进入delete的细节部分

结论: new等价为operato new和构造函数(先申请空间再构造),operato new调用了malloc,delete等价为operator delete和析构函数(先析构清理资源再释放空间),operator delete调用了free(operato new和operator delete是系统提供的全局函数)

2.new申请空间失败的处理方法

异常的捕获方法try和catch

3.一个例子理解new和delete的操作细节

分析

Mystack* ptr = new Mystack:

delete ptr + ptr=nullptr

delete ptr

ptr=nullptr

其他提醒

程序运行结果


承接CD30.【C++ Dev】类和对象(21) 内存管理(上)文章

1.new和delete的底层实现

测试代码分析

以下代码在VS2010上测试:

class Myclass
{
public:
	Myclass()
	{}
	~Myclass()
	{}
	int _val;
};

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

观察现象

单步调试,进入new的细节部分

发现调用了operator new,在operator new里面调用了malloc函数

但能说明new等价为operator new吗?

可以写代码验证看看:

按operator new的函数定义来看,参数写定义类型的大小,返回类型为void*,可能需要强制类型转换

为Myclass添加一个成员变量,如下:

class Myclass
{
public:
	Myclass()
		:_val(1)
	{}
	~Myclass()
	{}
	int _val;
};

int main()
{
	Myclass* ptr= (Myclass*)operator new (sizeof(Myclass));
	delete ptr;
	return 0;
}

下断点到delete ptr,监视窗口看看*ptr的_val,发现是随机值(未初始化),则得出结论:operator new没有调用构造函数

单步调试,进入delete的细节部分

发现调用了Myclass::`scalar deleting destructor'

进入Myclass::`scalar deleting destructor'后,发现调用了析构函数和operator delete

结论: new等价为operato new和构造函数(先申请空间再构造),operato new调用了malloc,delete等价为operator delete和析构函数(先析构清理资源再释放空间),operator delete调用了free(operato new和operator delete是系统提供的全局函数)

注:operator new[]实际多次调用operator new和构造函数,operator delete[]实际多次调用析构函数和operator delete

可由此推出:内置类型没有构造函数,因此new和operator new的作用是一样的,例如以下代码:

int* ptr1 = (int*)operator new(sizeof(int));
operator delete (ptr1);

int* ptr2 = new int;
delete ptr2;

(ptr1和ptr2在内存申请和释放上完全等价)

2.new申请空间失败的处理方法

malloc申请空间如果失败,会返回空指针,但是new和malloc不同,new申请空间失败会抛异常

(如果malloc申请空间,成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常) 

面向对象语言处理失败,不太会使用返回值,而是会抛异常!

VS2010的operator new的代码:

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
			static const std::bad_alloc nomem;//抛异常
			_RAISE(nomem);
		}

	return (p);
}

异常的捕获方法try和catch

当前先简单了解用法即可

例如有以下内存泄漏代码:

#include <iostream>
using namespace std;
int main()
{
	int* ptr;
	while (1)
	{
		ptr = new int[1024 * 1024 * 1024];
	}
	return 0;
}

程序运行一会就强行退出了:

使用try和catch捕获异常:

#include <iostream>
using namespace std;
int main()
{
	int* ptr;
	try
	{
		while (1)
		{
			ptr = new int[1024 * 1024 * 1024];
		}
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

运行结果:控制台窗口打印异常信息

3.一个例子理解new和delete的操作细节

提问:

1.Mystack* ptr = new Mystack;的new做了什么? 

2.delete ptr;的delete做了什么? 

#include <iostream>
using namespace std;
typedef int DataType;
class Mystack
{
public:
	Mystack(size_t capacity = 5)
	{
		cout << "构造函数: Mystack(size_t capacity = 5)" << endl;
		_arr = (DataType*)malloc(sizeof(DataType) * capacity);
		_capacity = capacity;
		_size = 0;
	}
	~Mystack()
	{
		cout << "析构函数: ~Mystack()" << endl;
		if (_arr)
		{
			free(_arr);
			_arr = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _arr;
	int _capacity;
	int _size;
};

int main()
{
	try 
	{
		Mystack* ptr = new Mystack;
		delete ptr;
		ptr = nullptr;
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

(注: delete ptr只是释放资源,不会自动将ptr置空,为了避免野指针的问题,应该手动将ptr置为空) 

分析

Mystack* ptr = new Mystack:

由之前的结论可知:new先申请空间再构造

先在堆区上为栈对象Mystack开辟空间,ptr在栈区上,且ptr指向Mystack对象,如下图:

(注:此时_arr仍然是野指针,暂时没有调用Mystack的构造函数)

调用构造函数后,如下图:

完整的图为:

delete ptr + ptr=nullptr

delete ptr

先调用析构函数~Mystack():释放_arr指向的空间,并为_arr置空,将_capacity和_size清零

再调用free()释放对象的空间:

(此时ptr为野指针)

ptr=nullptr

delete ptr只是释放资源,不会自动将ptr置空,为了避免野指针的问题,应该手动将ptr置为空

其他提醒

构造函数Mystack()中不用判断_arr是否为nullptr,因为new申请失败会抛异常,只需要使用try和catch捕获即可

int main()
{
	try 
	{
		Mystack* ptr = new Mystack;
		delete ptr;
		ptr = nullptr;
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

程序运行结果

下篇将介绍定位new表达式以及new和malloc,dele和free的区别总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值