内存管理(1)

1、各类型数据在内存中的存储空间

int globalVar = 1;
static int staticGlobalVar = 1;

void Test()
{
	static int staticVar = 1;
	int localVar = 1;

	int num1[10] = {1,2,3,4};
	char char2[] = "abcd";  //常量数据需要在外面加 " "
	const char* pChar3 = "abcd";

	int* ptr1 = (int*)malloc(sizeof(int)*4);
	int* ptr2 = (int*)calloc(4,sizeof(int));
	int* ptr3 = (int*)realloc(ptr2,sizeof(int)*4);
	free(ptr1);
	free(ptr2);
}


 globalVar(全局变量)           静态区 
 staticGlobalVal(静态全局变量) 静态区
 staticVar(静态局部变量)       静态区
 localVar(局部变量)            栈区
 num1(数组名)                    栈区
 char2(数组名)                 栈区
 *char2(字符串)                  代码段(存储常量数据)
 pChar3(指针)                     栈区
 *pChar3(指针解引用后为:字符串)  代码段
 ptr1(指针:指向堆区的一块儿空间) 栈区
 *ptr1                            堆区

2、C++内存管理方式

// C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete
// 操作符进行动态内存管理。

2.1 针对于内置类型分析

void Test()
{
	int* p1 = (int*)malloc(sizeof(int));
	int* p2 = new int;

	//申请具有5个int的数组
	int* p3 = new int[5];
	//申请1个int的数组,并初始化为5
	int* p4 = new int(5);

	//C++11支持new[] 用{}初始化  C++98不支持
	//将申请具有5个int的数组 进行初始化
	int* p5 = new int[5]{1,2,3};

	free(p1);
	delete p2;
	delete[] p3;
	delete p4;
	delete[] p5;

	//针对内置类型,new/delete 跟 malloc/free没有本质的区别,只有用法的区别。
	// new/delete 用法简化了。
}

int main()
{
	Test();
	
	return 0;
}

2.2 针对于自定义类型分析

class A
{
public:
	A(int a)
		:_a(a)
	{
		cout<<"A():"<< this << endl;
	}

	~A()
	{
		cout<< "~A():" <<this << endl;
	}

private:
	int _a;
};

int main()
{
	//堆上申请空间
	A* p1=(A*)malloc(sizeof(A));
	if (nullptr==p1)
	{
		perror("malloc fail");
		return 0;
	}

	//1、堆上申请空间  2、调用构造函数进行初始化
	A* p2 = new A;   //调用默认构造函数
	A* p2 = new A(10); //调用非默认构造函数

	 //申请10个A类型对象的空间,并进行初始化
	A* p3 = new A[5]{1,2,3,4,5};
	delete[] p3;  //数组里的对象,先初始化后析构
     
	  //释放空间
	free(p1);

	  //1、调用 析构函数 清理对象中资源  2、释放空间
	delete p2;

	  //结论: new/delete 是为自定义类型准备的;
	  //不仅在堆上申请出来,还会调用构造函数和析构函数进行初始化和清理。

	  //注意:new/delete  new[]/delete[]一定要匹配使用,否则可能会出问题。

	return 0;
}

2.3 C语言与C++在申请动态内存失败时的区别

int main()
{
	// malloc失败返回NULL
	char* p1 = (char*)malloc(1024u * 1024u * 1024u * 2 - 1);
	printf("%p\n",p1);

	// new失败,不需要检查返回值,它失败是抛异常(异常:是面向对象语言出错处理的方式)
	try
	{
		//char* p2 = new char[1024u * 1024u * 1024u*2-1];
		char* p2 = (char*)operator new(1024u * 1024u * 1024u);
		printf("%p\n", p2);
 
      operator delete(p2);
	}
	//当申请空间失败时,才会进入catch; 若申请空间成功时,就会跳过catch;
	catch (const exception& e)
	{
		cout<< e.what() <<endl;
	}


	return 0;
}

3、operator new 和 operator delete函数(重点)

3.1 底层知识解析

// new和delete 是用户进行动态内存申请和释放的操作符。operator new 和 operator delete是系统提供的全局函数,new在底层调用operator new全局函数来
// 申请空间,delete在底层通过operator delete全局函数来释放空间。
//
// operator new全局函数——帮助new开空间——(封装)调用malloc{ 若malloc失败了,符合C++ new的失败机制(失败抛异常)}。 
// operator delete全局函数——帮助delete释放空间——(封装)调用free 
//
// new的底层分为两部分:调用operator new +  调用构造函数; 即:new Type(自定义类型) --> call  operator new【调用malloc(若开辟空间失败,会抛异常)】 +  call Type构造函数
// delete的底层也分为两部分:调用operator delete + 调用析构函数;
//
//总结:在C++中,申请和释放堆上的空间,就用new 和 delete

3.2 实现专属operator new 与 operator delete (了解)

//注意:一般情况下不需要对 operator new 和 operator delete 进行重载,除非在申请和释放空间的时候具有某些特殊的要求。比如:在使用new和delete
// 申请和释放空间时,打印一些日志信息,来简单帮助用户检测是否存在内存泄漏。
//
//当我们不写自己专属的operator new函数和 operator delete函数的时候,new和delete 会自动调用C++库里面的operator new函数和 operator delete函数。
//当我们自己写专属的operator new函数和 operator delete函数时,new和delete 会调用专属的operator new函数和 operator delete函数来实现某些特殊的需求。

// new -> operator new + 构造函数
// 默认情况下,operator new使用全局库里面的。
// 但每个类可以去实现自己专属operator new;  new这个类对象,它就会调用自己实现的这个operator new




//实现类专属的operator new(优先调用)
struct ListNode
{
	int _val;
	ListNode* _next;

	//内存池
	static allocator<ListNode> alloc;

	void* operator new(size_t n)
	{
		cout<< "operator new -> STL内存池allocator申请" << endl;
		void* obj = alloc.allocate(1);
		return obj;
	}

	void operator delete(void* ptr)
	{
		cout<< "operator delete -> STL内存池allocator申请" << endl;
		alloc.deallocate((ListNode*)ptr,1);
	}

	//构造函数
	struct ListNode(int val)
		:_val(val)
		,_next(nullptr)
	{}
};

内存池的定义
allocator<ListNode> ListNode::alloc;

int main()
{
	//频繁地申请 ListNode;想提高效率 —— 申请ListNode时,不去malloc,而是自己定制内存池。
	ListNode* node1 = new ListNode(1); //new先去调用 类里面的operator new ,如果类里面没有operator new,就会去库里面调用。
	ListNode* node2 = new ListNode(2);
	ListNode* node3 = new ListNode(3);

	delete node1;
	delete node2;
	delete node3;

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值