文章写的很浅,请大佬指教
C/C++内存管理
前言
栈又叫堆栈,非静态局部变量/函数参数/返回值等等。
内存映射段是高效的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来申请和释放空间。
operator new实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛出异常(例如申请的空间超过操作系统给我们提供的空间)。operator delete最终通过free来释放空间。
来看下面这种情况:
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;
}
如果想定位在其他位置,则需要手动重载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;
}
使用场景:
定位new表达式在实际中一般是配合内存池使用,因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调用构造函数进行初始化。
总结
如何避免内存泄漏?
1.Windows下的#include<vld.h>;
2.智能指针;
3.良好的设计规范,事前预防。