堆和栈
每一篇博客背后,都是被面试官问到心态全崩的二狗
QAQ
| 栈 | 堆 | |
|---|---|---|
| 申请方式 | 系统自动分配 | 主动申请 |
| 系统响应 | 如果剩余空间大于申请空间则分配成功,否则分配失败栈溢出 | 堆在内存中呈现的方式类似于链表(记录空闲地址空间的链表),在链表上寻找第一个大于申请空间的节点分配给程序,将该节点从链表中删除,大多数系统中该块空间的首地址存放的是本次分配空间的大小,便于释放,将该块空间上的剩余空间再次连接在空闲链表上 |
| 空间分配 | 连续空间 | 不连续 |
| 申请效率 | 栈是有系统自动分配,申请效率高,但程序员无法控制 | 堆是由程序员主动申请,效率低,使用起来方便但是容易产生碎片 |
| 存放内容 | 局部变量,函数的参数 | 由程序员控制 |
| 生长方向 | 生长方式是向下的,也就是沿着内存地址减小的方向增长 | 生长方向是向上的,也就是沿着内存地址增加的方向 |
| 分配方式 | 两种分配方式:静态分配和动态分配,静态分配是编译器完成的,比如局部变量的分配;动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器实现的,无需我们手工实现 | 堆都是动态分配的,没有静态分配的堆 |
总体来说,栈的空间是要小于堆的。堆内存几乎是没有什么限制的;但是对于栈来讲,一般是有一定的空间大小的
c++中类的对象建立
静态建立: 直接调用类的构造函数
动态建立: 通过new创建
限制类的对象只能在堆上创建
思路1:将析构函数设为私有
静态对象建立在栈上,是由编译器分配和释放内存空间,编译器为对象分配内存空间时,会对类的非静态函数进行检查,即编译器会检查析构函数的访问性。当析构函数设为私有时,编译器创建的对象就无法通过访问析构函数来释放对象的内存空间,因此,编译器不会在栈上为对象分配内存
1 | |
问题:
无法从类的外部调用delete函数,此时需要定义一个public的destory()函数来析构对象
无法解决继承问题
因为如果这个类作为基类,析构函数要设置成 virtual,然后在派生类中重写该函数,来实现多态。但此时,析构函数是私有的,派生类中无法访问。
思路2: 将构造函数和析构函数都设为protected,并提供一个public的静态函数完成构造
解决了继承问题
1 | |
为什么create要设为static
因为如果要靠一个对象来创建另一个对象就显得很呆瓜…
1 | |
限制类的对象只能在栈上创建
这个就简单多了
因为在栈上创建就必须要用到new,只要把 new 设为私有就可以啦
奥不,还有delete
1 | |