https://blog.youkuaiyun.com/my_heart_/article/details/51726637
C/C++语言的内存分配方式:
从栈上分配:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是栈本身的容量有限
从堆上分配:这就是我们这里重点要说的动态内存分配,程序在运行的时候用malloc或new申请任意多少的内存空间,程序员自己负责在何时用free或delete释放内存.动态内存的生存期由用户决定,使用非常灵活,但问题也最多
从静态区上分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量、static变量
既然c++中有了可以动态开辟内存的函数为什么又要有new/delete呢?
C++中的malloc/free是继承C语言中的malloc/free,malloc只是单纯的开辟内存空间而不进行初始化,free只是将动态开辟的内存空间给释放了。
对于内置类型来说,malloc/free开辟和释放内存没有任何问题;对于非内置类型而言,由于对象创建过程中调用构造函数进行初始化,在对象的消除时要调用析构函数进行一些清理工作,显然,malloc/free无法完成这些事情。
因此,C++提供了new/delete两个操作符,用new在动态分配内存的时候调用构造函数进行初始化,delete在释放内存的时候自动调用析构函数进行清理。
new和delete的内部实现:
new的内部实现是通过调用一下函数实现的:
char* operator new(size_t count);
char* operator new[](size_t count);
delete内部是通过调用以下两个函数实现的:
void operator delete(char *p);
void operator delete(char *p);
malloc/free为防止内存泄漏,一定要成对出现。
new和delete成对出现:new开辟内存空间是调用构造函数创建对象,而如果不用delete释放空间而是用free,那么释放空间之前不会执行析构函数,有可能会导致内存泄漏。
malloc/free 和 new/delete横向对比:
它们都是动态管理内存的入口
malloc/free是C/C++的标准库函数,new/delete是C++的操作符
malloc需要手动计算类型的大小且返回值是void*,new是自己计算类型的大小,返回对用类型的指针
malloc/free只是动态分配内存空间/释放空间,new/delete除了完成空间的分配外还会调用构造函数和析构函数对对象成员进行初始化/清理
malloc、calloc、realloc的使用:
这三个函数都在 stdlib.h 函数库内,它们的标准声明分别为:
void* malloc(unsigned size);
void* calloc(size_t numElements, size_t sizeOfElement);
void* realloc(void* ptr, unsigned newsize);
它们的返回值都是请求系统分配的地址,如果请求失败就返回NULL
malloc():参数size为需要内存空间的长度,该函数是在内存的动态存储区中分配一块长度为size字节的连续区域,返回该区域的首地址
calloc():与malloc相似,numElements为元素个数,参数sizeOfElement为申请地址的单位元素长度,即在内存中申请numElements*sizeOfElement字节大小的连续地址空间
realloc():给一个已经分配了地址的指针重新分配空间,参数ptr为原有的空间地址,newsize是重新申请的地址长度
malloc、calloc、realloc的区别:
函数malloc不能初始化所分配的内存空间,而函数calloc能.如果由malloc()函数分配的内存空间原来没有被使用过,则其中的每一位可能都是0;反之, 如果这部分内存曾经被分配过,则其中可能遗留有各种各样的数据.也就是说,使用malloc()函数的程序开始时(内存空间还没有被重新分配)能正常进行,但经过一段时间(内存空间已经被重新分配)可能会出现问题。
函数calloc() 会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为0;如果你是为指针类型的元素分配内存,那么这些元素通常会被初始化为空指针;如果你为实型数据分配内存,则这些元素会被初始化为浮点型的零
realloc可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或是缩小,原有内存的中内容将保持不变.当然,对于缩小,则被缩小的那一部分的内容会丢失。realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址。相反,realloc返回的指针很可能指向一个新的地址
realloc是从堆上分配内存的.当扩大一块内存空间时,realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平;如果数据后面的字节不够,那么就使用堆上第一个有足够大小的自由块,然后现存的数据就被拷贝至新的位置,而旧块则放回到堆上.
注意:三个函数返回类型都是void*类型。void*表示的是未确定类型的指针,我们无法直接使用开辟的空间。C/C++规定,void* 类型可以强制转换为任何其它类型的指针,转换成一个确定的类型之后才可以使用开辟的空间