new与malloc的区别,delet和free的区别及其内部实现
new 与 malloc的区别:
- new 是运算符,malloc是库函数
- new会调用构造函数,malloc只申请内存
- new返回指定类型的指针,malloc返回void指针
- new自动计算所需的内存大小,malloc需要手动设置空间
- new可以被重载
内部实现:
delete 和 free 的区别:
- delete 是运算符,free是库函数
- delete会调用析构函数,free是会释放内存
- 使用free之前要检查指针是否为空指针,delete不需要,对空指针delete没有问题
- free 和 delete 不能混用,也就是说new 分配的内存空间最好不要使用使用free 来释放,malloc 分配的空间也不要使用 delete来释放
内部实现:
malloc, calloc, realloc, 和 alloca 申请内存的区别
- calloc 是申请N个大小为S的空间,且会初始化空间值为0;malloc不会初始化,是随机的垃圾数据(在VS Debug模式下,会是0xcccccc这种特殊值,为了调试方便)
- malloc 是在堆上申请大小为S的一个空间,但不会初始化
- realloc 是将原本分配的内存扩充到新的大小,要求新的大小必须大于原大小
- alloca 是在栈上申请空间,不需要(不能)使用free,运行到作用域以外的时候释放申请的空间
C++内存模型(堆、栈、静态区)
堆 heap :
由new分配的内存块,其释放编译器不去管,由我们程序自己控制(一个new对应一个delete)。如果程序员没有释放掉,在程序结束时OS会自动回收。涉及的问题:“缓冲区溢出”、“内存泄露”
栈 stack :
是那些编译器在需要时分配,在不需要时自动清除的存储区。存放局部变量、函数参数。存放在栈中的数据只在当前函数及下一层函数中有效,一旦函数返回了,这些数据也就自动释放了。函数栈内的变量地址总是连续的,从高地址向低地址生长。
全局/静态存储区 (.bss段和.data段) :
全局和静态变量被分配到同一块内存中。在C语言中,未初始化的静态变量放在.bss段中,初始化的放在.data段中;在C++里则不区分了。
常量存储区 (.rodata段) :
存放常量,不允许修改(通过非正当手段也可以修改)
代码区 (.text段) :
存放代码(如函数),不允许修改(类似常量存储区),但可以执行(不同于常量存储区)
根据c/c++对象生命周期不同,c/c++的内存模型有三种不同的内存区域,即
自由存储区(栈区):局部非静态变量的存储区域,即平常所说的栈
动态存储区(堆区): 用operator new ,malloc分配的内存,即平常所说的堆
静态存储区:全局变量 静态变量 字符串常量存在位置
注意:
栈区变量要注意析构函数的调用次序,由于是先进后出,则先创建的对象,最后被析构。
堆与栈的区别
- 堆是先进先出,栈是先进后出。
- 栈的大小固定,受限于系统中有效的虚拟内存,可能会发生栈溢出;堆可以动态生长
- 栈的空间有系统释放,堆内存由程序员释放
- 堆容易产生碎片
- 申请方式上,栈是系统自动分配,堆是由程序员申请
如何实现只能动态分配类对象,不能定义类对象
即只能将对象创建于堆上,不能创建于栈上。需要把构造函数和析构函数设为protected,派生类可以访问,外部无法访问。同时创建create和destroy函数,在内部调用构造和析构,用于创建和删除对象。其中create设为static,使用类名访问。
|
|
如何实现只能在栈上创建对象, 不能在堆上创建对像
在堆上创建对象的唯一方法是使用new关键字,所以,只需要禁用new关键字就可以了。将operator new 设为私有的, 外部不可访问。
|
|
析构函数什么时候声明为私有?什么时候不能声明为私有?
私有析构函数可以使得对象只在堆上构造。在栈上创建的对象要求构造函数和析构函数必须都是公有的,否则编译器报错“析构函数不可访问”;而堆对象由程序员创建和删除,可以把析构函数声明为私有的。由于delete会调用析构函数,而私有的析构无法被访问,编译器报错,此时通过增加一个destroy()方法,在方法内调用析构函数来释放对象:
|
|
析构函数不能声明为私有的情况:基类的析构函数不能声明为私有,因为要在派生类的析构函数中被隐式调用。
构造函数什么时候声明为私有?什么时候不能声明为私有?
单例模式时构造函数声明为私有。
基类的构造函数不能声明为私有,因为要在派生类的构造函数中被隐式调用。如果在派生类的构造函数中没有显式调用基类的构造,则会调用基类的默认构造函数。