Cpp05 — 内存管理

内存管理

代码是以文件的形式存储在磁盘上的。

Cpp05 — 内存管理_第1张图片

不是说是代码就会加载到代码段,而是代码编译好的二进制指令代码会加载到代码段,然后程序中main函数执行时就是在代码段取指令来执行。栈和堆上的数据是运行时才建立的。

常量区是有硬件保护的,只要去访问,就会报错

Cpp05 — 内存管理_第2张图片

Cpp05 — 内存管理_第3张图片

Cpp05 — 内存管理_第4张图片

Cpp05 — 内存管理_第5张图片

new、delete、malloc、free

new、malloc

new是一个操作符,malloc是函数

int* p1 = new int;//申请1个int

int* p2 = new int[5];//申请有5个int元素的数组

int* p3 = new int(5);//申请1个int对象,初始化为5

new不会初始化,除非有指定。

C++98不支持new时初始化数组,C++11支持

int* p4 = new int[5]{1,2,3,4,5};

A* p3 = new A[2]{A(1), A(2)};

注意:数量要匹配,不会帮补0的

delete、free

delete p1;

delete []p2;//释放多个空间,[]中不用写东西

new和delete数量要匹配,不匹配有时候会报警告。

Cpp05 — 内存管理_第6张图片

Cpp05 — 内存管理_第7张图片

关键字、操作符:new、delete   函数:malloc、free

对于内置类型:new\delete与malloc\free没有本质区别,只是new和delete用法简化了一点。

对于自定义类型:有很大的区别。new对于自定义类型不仅会开空间,还会去调用它的构造函数去初始化,而malloc没有。(delete会调用其析构函数然后释放空间)

区别:

1.new在申请空间时还会调用其构造函数初始化,不提供默认构造函数的话会报错,即使没有,也可以传参,传了就没错了。

2.delete调用析构函数清理对象中的资源,然后释放空间

结论:new/delete是为内置类型准备的,不仅在堆上申请出来,还会调用构造和析构清理

3.malloc失败是返回NULL,一般不会失败,除非开的空间太大了,或者内存不够了,cout打印char*时,打印出来的不是地址,而是字符串,int*那些的不会出现这样的问题,因为会觉得它是指针。而new失败是抛异常,new失败不需要检查返回值,因为它失败是抛异常,异常是面向对象语言处理错误的一种方式,与继承和多态有关

因为申请的是虚拟内存,所以与电脑配置无关,虚拟内存的大小都是4G

free之后,数据还在,只是我们没有它的访问权限了,没有对它直接使用的权限了。

先定义的先构造、后析构

底层原理

其实new的底层是调用了两个函数,即调用operator new去堆上开空间,调用构造函数去初始化,这里的operator new不是对new的重载,而是一个全局函数,其底层是调用malloc开空间。

Cpp05 — 内存管理_第8张图片

operator new存在的意义:封装malloc,帮助new开空间,为什么不直接调malloc呢?这样处理符合C++new的失败机制(失败抛异常)。

Cpp05 — 内存管理_第9张图片Cpp05 — 内存管理_第10张图片

Cpp05 — 内存管理_第11张图片

(其实operator new就可以了,只是为了成一对才有operator delete)

operator new我们也可以直接使用,其实和new是一样的

重载operator new和operator delete,比如我们想检测内存泄漏,重载一下就可以

::域作用限定符,如果没写的话还是调的是库里的,调用的时候可以这么调,建议是对new和delete进行宏替换,这样就会调到它们

原理:

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足。应对措施,如果应对措施用户设置了,则继续申请,否则抛异常。
*/

/*
operator delete: 该函数最终是通过free来释放空间的 
*/

/*
free的实现 
*/
#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果 
malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。

重载:

// 重载operator delete,在申请空间时:打印在哪个文件、哪个函数、第多少行,申请了多少个 
字节
void* operator new(size_t size, const char* fileName, const char* funcName, 
size_t lineNo)
{
void* p = ::operator new(size);
cout << fileName << "-" << funcName << "-" << lineNo << "-" << p << "-" 
<< size << endl;
return p; 
}
// 重载operator delete,在释放空间时:打印再那个文件、哪个函数、第多少行释放
void operator delete(void* p, const char* fileName, const char* funcName, 
size_t lineNo)
{
cout << fileName << "-" << funcName << "-" << lineNo << "-" << p << 
endl;
    ::operator delete(p); 
}
int main() 
{
// 对重载的operator new 和 operator delete进行调用
int* p = new(__FILE__, __FUNCTION__, __LINE__) int; 
operator delete(p, __FILE__, __FUNCTION__, __LINE__); 
return 0;
}
// 上述调用显然太麻烦了,可以使用宏对调用进行简化
// 只有在Debug方式下,才调用用户重载的 operator new 和 operator delete
#ifdef _DEBUG
#define new new(__FILE__, __FUNCTION__, __LINE__)
#define delete(p) operator delete(p, __FILE__, __FUNCTION__, __LINE__) 
#endif
int main() 
{
int* p = new int; 
delete(p); 
return 0;
}

重载一个类专属的operator new

当一个结点需要被频繁开辟,需要频繁申请,效率就比较低,语言里面有一个池化技术,我们可以申请一个内存池。C++的库里有一个内存池:allocator第十节3:20:00到完

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在释放空间前会调用析构函数完成 
空间中资源的清理

语法使用的区别、本质功能的区别

Cpp05 — 内存管理_第12张图片

 Cpp05 — 内存管理_第13张图片

Cpp05 — 内存管理_第14张图片

第十节 3:20:00

Cpp05 — 内存管理_第15张图片

 Cpp05 — 内存管理_第16张图片

Cpp05 — 内存管理_第17张图片

Cpp05 — 内存管理_第18张图片

定位new表达式

定位new是在已有内存空间中调用构造函数初始化一个对象。即创建空间后,想对已创建的对象进行初始化时使用。

使用格式:new(place_address)type或new(place_address)type(initializer_list)

 ​​​​​Cpp05 — 内存管理_第19张图片

你可能感兴趣的:(算法,数据结构)