堆和栈

每一篇博客背后,都是被面试官问到心态全崩的二狗

QAQ

申请方式 系统自动分配 主动申请
系统响应 如果剩余空间大于申请空间则分配成功,否则分配失败栈溢出 堆在内存中呈现的方式类似于链表(记录空闲地址空间的链表),在链表上寻找第一个大于申请空间的节点分配给程序,将该节点从链表中删除,大多数系统中该块空间的首地址存放的是本次分配空间的大小,便于释放,将该块空间上的剩余空间再次连接在空闲链表上
空间分配 连续空间 不连续
申请效率 栈是有系统自动分配,申请效率高,但程序员无法控制 堆是由程序员主动申请,效率低,使用起来方便但是容易产生碎片
存放内容 局部变量,函数的参数 由程序员控制
生长方向 生长方式是向下的,也就是沿着内存地址减小的方向增长 生长方向是向上的,也就是沿着内存地址增加的方向
分配方式 两种分配方式:静态分配和动态分配,静态分配是编译器完成的,比如局部变量的分配;动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器实现的,无需我们手工实现 堆都是动态分配的,没有静态分配的堆

总体来说,栈的空间是要小于堆的。堆内存几乎是没有什么限制的;但是对于栈来讲,一般是有一定的空间大小的

c++中类的对象建立

静态建立: 直接调用类的构造函数

动态建立: 通过new创建

限制类的对象只能在堆上创建

思路1:将析构函数设为私有

静态对象建立在栈上,是由编译器分配和释放内存空间,编译器为对象分配内存空间时,会对类的非静态函数进行检查,即编译器会检查析构函数的访问性当析构函数设为私有时,编译器创建的对象就无法通过访问析构函数来释放对象的内存空间,因此,编译器不会在栈上为对象分配内存

1
2
3
4
5
6
7
8
9
10
11
12
13
class A
{
public:
A() {}

void destory()
{
delete this;
}

private:
~A(){}
};

问题:

无法从类的外部调用delete函数,此时需要定义一个public的destory()函数来析构对象

无法解决继承问题

因为如果这个类作为基类,析构函数要设置成 virtual,然后在派生类中重写该函数,来实现多态。但此时,析构函数是私有的,派生类中无法访问。

思路2: 将构造函数和析构函数都设为protected,并提供一个public的静态函数完成构造

解决了继承问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A
{
protected:
A() {}
~A() {}

public:
static A *create()
{
return new A();
}
void destory()
{
delete this;
}
};

为什么create要设为static

因为如果要靠一个对象来创建另一个对象就显得很呆瓜…

1
2
A* p=old_A.create();//好难看,而且第一个old_A从哪里creat捏
A* p=A::create();//正常多了

限制类的对象只能在栈上创建

这个就简单多了

因为在栈上创建就必须要用到new,只要把 new 设为私有就可以啦

奥不,还有delete

1
2
3
4
5
6
7
8
9
class A
{
private:
void *operator new(size_t t) {} // 注意函数的第一个参数和返回值都是固定的
void operator delete(void *ptr) {} // 重载了 new 就需要重载 delete
public:
A() {}
~A() {}
};