常常被人问到,会不会写C++,曾经以为了解对面对象编程,了解qt等开源的库之后,就可以称之为会写C++了。但是深入了解之后就会发现,C++其实并不是这么简单。作为本专题的第一篇记录,将从内存分配机制开始深入的剖析C++。
一 C++ 内存分配方式
在C++中内存被分为五个区分别是:堆、栈、自由存储区、全局/静态存储区、常量存储区。
- 栈:是分配给函数局部变量的存储单元,函数结束后,该变量的存储单元自动释放,效率高,分配的空间有限。
- 堆:由new创建,由delete释放的动态内存单元。如果用户不释放该内存,程序结束时,系统会自动回收。
- 自由存储区:由malloc创建,由free释放的动态内存单元,与堆类似。
- 全局(静态)存储去:全局变量和静态变量占一块内存空间。
- 常量存储区:存储常量,内容不允许更改。
引用自ladybai
一般而言对于程序员,我们只需要去关注堆和栈的概念。相比堆,栈大量减少了内存的碎片问题,并且计算机在系统底层提供专门的指令执行,而new的机制相比更为复杂所以分配效率相较于栈更慢。
二 内存分配失败
根据许多血一般的教训,下列的代码在动态分配内存的时候至关重要。
1 | object* c = new object(); |
但是其实在较新的C++标准中,出现内存分配失败时会抛出
1 | std::bad_alloc |
但是针对这个我们主要需要意识到一个问题,内存的分配可能失败。
三 new/operator new/placement new
为了防止反复的释放内存,C++除了最基本的new操作之外还提供了placement new的操作。下面简单介绍这三种不同的new操作
- 运算符 new = 先调用函数 operator new 分配空间 + 然后调用构造函数。
- 对于operator new 函数内部,他是通过再调用malloc函数,进行空间分配的(当然也可以重写一个自己的空间分配器)。
- placement new 指的是,不进行分配空间,而是在指定的空间上面进行调用构造函数。当然,在析构的时候,也只能显示的调用析构函数。(因为并不是真正的释放空间)
引用自爱秋刀鱼的猫
下面简单给出new的代码。
1 | object* a = new object(); |
那么其实来说就是上面的两种new,然后operator new的含义应该是仅分配内存但是不初始化函数。
针对大多数场景,我们使用普通的new可以完成绝大多数任务。但是极少数情况,我们可能需要反复利用一块极大的内存空间,此时利用placement new可以减少内存空间的申请释放所消耗的时间。
四 总结
本篇主要简要介绍了C++内存分配的机制,并且了解了针对大块内存反复申请释放采用placement new的操作。本模块将持续更新,介绍更多关于C++更为深入的内容。