在C++中,你真的会用new吗?

摘要:“new”是C++的一个关键字,同时也是操做符。关于new的话题很是多,由于它确实比较复杂,也很是神秘。

本文分享自华为云社区《如何编写高效、优雅、可信代码系列(2)——你真的会用new吗》,原文做者:我是一颗大西瓜 。程序员

C++内存管理

1. C++内存分配

C++中的程序加载到内存后按照代码区、数据区、堆区、栈区进行布局,其中数据区又能够分为自由存储区、全局/静态存储区和常量存储区,各区所长以下:数组

  • 栈区
    函数执行的时候,局部变量的存储单元都在栈上建立,函数执行结束后存储单元会自动释放。栈内存分配运算内置于处理器指令集中,效率高,但分配内存容量有限。
  • 堆区
    堆就是new出来的内存块,编译器无论释放,由应用程序控制,new对应delete。若是没释放掉,程序结束后,操做系统会自动回收。
  • 自由存储区
    C中malloc分配的内存块。用free结束生命周期。
  • 全局/静态存储区
    全局变量和静态变量被分配到同一块内存中,定义的时候就会初始化
  • 常量存储区
    比较特殊的存储区,存放常量,不容许修改。

堆和栈的区别函数

  • 管理方式
    栈由编译器自动管理,堆由程序员控制
  • 空间大小
    32位系统下,堆内存能够达到4GB,栈有必定的空间大小
  • 碎片管理
    对于堆,频繁的new/delete确定形成内存空间的不连续,产生大量内存碎片下降程序效率;栈因为遵循先进后出的规则,不会产生空隙
  • 生长方向
    堆是向上生长的,即向着内存地址增长的方向增加;而栈是向着内存地址减少的方向增加的
  • 分配方式
    堆是动态分配的,栈有动态分配和静态分配之分:静态分配由编译器完成,动态分配由alloca函数完成,即便是动态分配,依然是编译器自动释放
  • 分配效率
    计算机底层提供了栈的支持,分配了专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这决定了栈的效率会比较高。堆则是由C/C++函数库提供的,机制比较复杂,好比为了分配某个大小的内存须要在堆内存中搜索可用足够大小的空间,效率比栈要低的多

2. new/delete和new []/delete []

  • 回收new分配的单个对象内存空间时用delete,回收用new[]分配的一组对象时用delete[]
  • 对于内置类型(int/double/float/char/…),因为new[]申请内存时,编译器还会悄悄在内存中保存整数,表示指针数组的个数,因此delete/delete[]均可以正确释放所申请的内存空间
  • 建议在调用new时使用的[],那么调用delete也使用[]

3. new的三种形态

  • new operator 经常使用的new,语言函数内建,不能重载。调用过程当中实际完成的有三件事:
  1. 为类型对象分配内存;
  2. 调用构造函数初始化内存对象;
  3. 返回对象指针
    若是是在堆上创建对象,直接使用new operator。
  • operator new 普通操做符,能够重载。若是仅仅是分配内存,那么应该调用operator new,但不负责初始化。系统默认提供的分配器在时间和空间两方面都存在一些问题:分配器速度较慢,分配小型对象时空间浪费严重,重载new/delete有三方面好处:
  1. 改善效率
  2. 检测代码中的内存错误
  3. 得到内存使用的统计数据
  4. C++标准规定,重载的operator new必须是类成员函数或全局函数,全局的operator new重载不该该改变原有签名,而是直接无缝替换原有版本。全局重载颇有侵略性,别人使用你的库没法使用默认的new,而具体类的重载只会影响本class和其派生类,可是类的operator new函数重载必须声明为static,由于operator new是在类的具体对象被构建出来以前调用的。
  5. 为了得到2和3的优点,重载的operator new须要以下函数声明void* operator new(size_t, const char* file, int line);
  • placement new 定义在库<<new>>中。若是想在一块已经得到内存里创建对象,那么应该调用placement new。一般状况不建议使用,但在某些对时间要求很是高的应用中能够考虑,由于选择合适的构造函数完成对象初始化是一个时间相对较长的过程。

 

点击关注,第一时间了解华为云新鲜技术~布局

相关文章
相关标签/搜索