C++探幽:内存分配

内存对象的基本概念

栈对象

栈,一般用于存放局部变量或对象。
优势在于:能够在适当的时候自动生成、在适当的时候自动销毁。栈对象的创建(只需要移动栈顶指针)速度比堆对象的创建速度块(需要执行某种空间搜索算法)。
缺点:栈空间容量一般较小(1M-2M),体积比较大的对象不适合在栈中分配。而且递归函数最好不适用栈对象,因为随着递归调用深度的增加,所需的栈空间也会线性增加,从而导致栈溢出。

int add(int a,int b){return a+b;}
int mian()
{
	int a=2,b=0;
	int c=add(a,b);
}

下边这个例子中:

  1. 在函数add中,会生成两个局部变量a_,b_,返回的时候会生成另外一个局部变量c_。
  2. 在c=add(a,b)中,执行了c=c_的语句,c_是一个临时变量,在赋值完成后一段时间内被释放。
    所以编译器在我们不知不觉的情况生成了好多临时变量和对象,所以一般的如果函数需要传递大的参数,就需要使用const 引用的方式实现,以节约系统的资源。

堆对象

堆——自由存储区,在程序执行过程中动态分配,所以最大的特性就是动态性。所有堆对象的创建和销毁都由程序员负责(new/delete)。
容易出现的内存错误:

  1. 内存泄漏:分配了堆对象,但是忘记释放;
  2. 悬挂指针:释放了对象,没有将指针置NULL;
    适用new分配堆对象的时候,会调用operator new操作,operator new会执行某种空间搜索算法,该搜索过程会比较耗费时间。所以建立堆对象比栈对象慢。

静态存储区

所有的静态对象、全局对象都于静态存储区分配
关于全局对象,是在main函数执行前就分配好了的,在main函数执行前,编译器会生成_main函数进行所有全局对象的构造和初始化操作。在main函数结束之前,会调用由编译器产生的exit函数,来释放所有的全局对象。

void main(void)
{
 _main(); //隐式代码,由编译器产生,用以构造所有全局对象
 … … // 显式代码
 … …
 exit() ; // 隐式代码,由编译器产生,用以释放所有全局对象
}

对于局部静态对象,是在函数中定义的,类似于栈对象,但是多了一个关键字static。它的生命周期是从其所在的函数第一次被调用执行到该静态对象的声明代码时,直到整个程序结束时,才销毁该对象。
而作为类的静态成员,类的静态成员对象伴随着第一个类的对象的产生而产生,在整个程序结束时消亡。如果创建了多个类对象,则这些类对象共享该静态成员(该静态成员属于类,而不属于某一个对象)
如果一个含有静态成员的类作为基类被继承了,其基类、子类也是共享该静态成员的。所以当需要在这些class之间或这些class objects之间进行数据共享或通信时,这样的静态成员无疑是很好的选择。

智能指针封装资源

启发

栈对象自动释放时,会调用自己的析构函数。如果在栈对象中封装资源,而且在栈对象的析构函数中执行释放资源的动作,那么资源泄漏的概率就会大大降低,因为栈对象可以自动释放资源,即使是再所在函数发生异常的时候。

实际的过程是这样的:函数抛出异常时,会发生所谓的stack_unwinding(堆栈回滚),即堆栈会展开,由于是栈对象,自然存在于栈中,所以在堆栈回滚的过程中,栈对象的析构函数会被执行,从而释放其所封装的资源。除非在析构函数执行的过程中再次抛出异常――而这种可能性是很小的,所以用栈对象封装资源是比较安全的。基于此认识,就可以创建一个自己的句柄或代理来封装资源了(智能指针应该就是使用了这种技术)。

摘自参考博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值