浅析C/C++的内存管理

文章写的很浅,请大佬指教

C/C++内存管理

  • 前言
  • 一、C语言中动态内存管理方式
  • 二、C++内存管理方式
    • 1.new和delete操作符
    • 2.操作符new和delete
    • 3.new和delete的实现原理
    • 4.定位new表达式(placement-new)
  • 总结


前言

浅析C/C++的内存管理_第1张图片
栈又叫堆栈,非静态局部变量/函数参数/返回值等等。
内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享内存,做进程间通信。
堆用于程序运行时动态内存分配。
数据段,存储全局数据和静态数据。
代码段,可执行的代码/只读常量。


提示:以下是本篇文章正文内容,下面案例可供参考

一、C语言中动态内存管理方式

C语言动态内存管理
C语言内存管理方式在C++中可以继续使用,但不推荐。

二、C++内存管理方式

1.new和delete操作符

通过new和delete两个操作符可以操作内置类型和自定义类型

class Test
{
public:
	Test():data(0)
	{}
private:
	int data;
};
int main()
{
	//内置类型
	int *ptr1 = new int;//动态申请一个int类型空间
	int *ptr2 = new int(1);//动态申请一个int类型空间并初始化为1
	int *ptr3 = new int[3];//动态申请3个int类型的空间
	delete ptr1;
	delete ptr2;
	delete[] ptr3;
	//自定义类型
	Test* t1 = new Test;//申请单个Test类型的对象
	delete t1;
	Test* t2 = new Test[10];//申请10个Test类型的对象
	delete[] t2;
	return 0;
}

可以在申请单个自定义类型的同时传值初始化,但不可在申请多个自定义类型对象空间的同时再给值初始化。

在申请自定义类型的空间时,new是先申请空间,再调用构造函数,delete会先调用析构函数,再释放空间。

2.操作符new和delete

重载new的原则:
1.第一个参数一定为size_t;
2.void* 返回。
重载new的原则:
1.第一个参数一定为void*类型的指针;
2.void 返回。

void* operator new(size_t size)
{
	void* ptr = malloc(size);
	return ptr;
}
void operator delete(void* ptr)
{
	free(ptr);
}
class Test
{
public:
	Test(int d = 0):data(d)
	{}
	~Test()
	{}
private:
	int data;
};
int main()
{
	Test* t = new Test(10);
	delete[] t;
	return 0;
}

当创建t对象时,先调用operator new,然后在调用构造函数,size会自动计算出来。释放空间时先调用operator delete,然后再调用析构函数。

本质上operator new和operator delete是系统提供的全局函数,new操作符和delete操作符在底层调用operator new 和operator delete来申请和释放空间。

浅析C/C++的内存管理_第2张图片
operator new实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛出异常(例如申请的空间超过操作系统给我们提供的空间)。operator delete最终通过free来释放空间。

来看下面这种情况:
浅析C/C++的内存管理_第3张图片

3.new和delete的实现原理

1.内置类型:
如果申请的是内置类型的空间,new和malloc及delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,连续空间需要加[],且new在申请空间失败时会抛出异常(在真实的C++运行库中,支持new_handler在申请失败时给与程序进行补救的机会、还可能会抛出bad_alloc异常等),malloc则会返回空。
2.自定义类型:
使用new时会调用系统的operator new函数申请空间,然后再申请的空间上执行构造函数;使用delete时会先在原有的空间上执行析构函数,完成对象中资源的清理工作,调用operator delete函数释放对象的空间。


4.定位new表达式(placement-new)

想要定位new首先得有原有空间,
暨定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new(place_address)type或者new(place_address)type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表

int main()
{
	//int *ptr = (int*)malloc(sizeof(int)* 10);//提前申请好空间
	int ptr[10] = { 0 };
	//定位new
	new(ptr) int(100);
	return 0;
}

浅析C/C++的内存管理_第4张图片
如果想定位在其他位置,则需要手动重载new;

void* operator new(size_t size, void* ptr, int pos)
{
	return &((int*)ptr)[pos];
}
int main()
{
	//int *ptr = (int*)malloc(sizeof(int)* 10);//提前申请好空间
	int ptr[10] = { 0 };
	//定位new
	new(ptr,5) int(100);
	return 0;
}

浅析C/C++的内存管理_第5张图片
使用场景:
定位new表达式在实际中一般是配合内存池使用,因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调用构造函数进行初始化。

总结

如何避免内存泄漏?
1.Windows下的#include
2.智能指针;
3.良好的设计规范,事前预防。

你可能感兴趣的:(c++,内存管理,重载)