C/C++的内存管理

版权声明:原创文章,转载请声名。 https://blog.csdn.net/qq_40707451/article/details/85261774

C/C++内存分布

  • 代码段:可执行的代码、只读常量
  • 全局数据区:存储全局数据和静态数据(static修饰)
  • 堆区:使用malloc、calloc、realloc等申请的空间
  • 栈区:非静态局部变量、函数参数、返回值等等

 C/C++语言中动态内存管理方式

C中使用malloc/calloc/realloc申请堆上的空间,和栈申请空间不同的是,堆上的空间需要编程人员自己调用函数free()释放。

malloc和free
malloc用来动态内存的开辟:

void* malloc(size_t size)

  • 这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针;
  • 如果开辟成功,则返回一个指向开辟好空间的指针;
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查;
  • 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。

free函数用来释放动态开辟的内存:

void free(void *ptr)

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的;
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。

calloc

void* calloc(size_t num,size_t size)

  • 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0;
  • 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。 

realloc

void *realloc(void *ptr,size_t szie)

  • ptr 是要调整的内存地址,size 调整之后新大小;
  • 返回值为调整之后的内存起始位置;
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。

malloc、calloc、realloc三者的区别

calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据;realloc也不会对所申请的内存空间进行初始化,但它让内存动态空间管理更加灵活。三者都申请空间成功返回空间的首地址,否则返回NULL。

在C++ 中单个元素的空间使用new来申请,delete来释放;多个元素的空间使用new[ ]来申请,delete[ ]来释放;不能交叉使用。

这里需要注意,new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operatornew全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

new的原理
1. 调用operator new函数申请空间
2. 在申请的空间上执行构造函数,完成对象的构造
delete的原理
1. 在空间上执行析构函数,完成对象中资源的清理工作
2. 调用operator delete函数释放对象的空间

new T[N]的原理
1. 调用operator new[ ]函数,在operator new[ ]中实际调用operator new函数完成N个对象空间的申

2. 在申请的空间上执行N次构造函数
delete[ ]的原理
1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
2. 调用operator delete[ ]释放空间,实际在operator delete[]中调用operator delete来释放空间

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

  • new (place_address) type或者new (place_address) type(initializer-list)
  • place_address必须是一个指针,initializer-list是类型的初始化列表

使用场景

定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义
类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。


malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。

malloc/free和new/delete的区别

  1.  malloc和free是函数,new和delete是操作符
  2.  malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
  7. new/delete比malloc和free的效率稍微低点,因为new/delete的底层封装了malloc/free

代码说明

#include<iostream>
#include<stdlib.h>
using namespace std;
//内存空间管理
class Test
{
public:
	Test(int data=1)
		: _data(data)
	{
		cout << "Test():" << this << endl;
	}
	~Test()
	{
		cout << "~Test():" << this << endl;
	}

private:
	int _data;
};
void Test1()
{
	// 申请单个Test类型的空间
	Test* p1 = new Test;
	delete p1;
	//申请多个Test类型的空间
	Test *p2 = new Test[10];
	//delete[]所释放的字节数为10*sizeof(test)+1,表示申请空间的大小+用于存放申请元素个数所占用的一个字节
	delete[]p2;
}
void Test2()
{
	//p现在指向的只不过是与Test对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
	Test *p = (Test*)malloc(sizeof(Test));
	//定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义
   //类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
	new(p) Test();
}

/*
*让一个类只能在堆上创建对象;
*创建对象有两个途径:1.调用构造函数   2.调用拷贝构造函数 
*封锁这两个途径
*/
class Test3 {
public:
	//提供在堆上创建对象的函数
	static Test3 *HeapCreate()
	{
		return new Test3;
	}
	
private:
	//声名构造函数和拷贝构造函数为私有(C++98)
	Test3() {};
	Test3(const Test3&) {};
	//C++11
	/*Test3(const Test3&)=delete;*/
};

/*
*让一个类只能在栈上创建对象;
*在堆上创建对象的途径:1.new  2.new[]  但new[]是对new多次使用,所以只需封锁new
*/
class Test4{
public:
	 Test4()
	 {}

private:
	void* operator new(size_t size){}//一般封锁了new,同时也封锁delete
	void operator delete(void *ptr){}
};

int main()
{
	//Test1();
	//Test2();
	//Test3 *p = Test3::HeapCreate();
	//Test4 *p=new Test4;
	
 	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40707451/article/details/85261774