`

C++:在堆上创建对象,还是在栈上

 
阅读更多

转自:http://www.devbean.net/2014/02/cpp-create-object-on-heap-or-stack/

 

如果需要在堆上创建对象,要么使用new运算符,要么使用malloc系列函数。这点没有异议。

真正有异议的是下面的代码:

 

 

此时,obj是在栈上分配的吗?

要回答这个问题,我们首先要理解这个语句是什么意思。这个语句就是代表着,在栈上创建对象吗?

其实,这行语句的含义是,使对象obj具有“自动存储(automatic storage)”的性质。所谓“自动存储”,意思是这个对象的存储位置取决于其声明所在的上下文。

如果这个语句出现在函数内部,那么它就在栈上创建对象。

如果这个语句不是在函数内部,而是作为一个类的成员变量,则取决于这个类的对象是如何分配的。考虑下面的代码:

 

 

指针pClass所指向的对象在堆上分配空间。因为Object obj;语句的含义是“自动存储”,所以,pClass->obj也是在堆上创建的。

理解了这一点,再来看下面的语句:

 

 

Object *pObj;代表,指针pObj是自动存储的,仅此而已,没有任何其它含义。而下面一行语句则指出,这个指针所指向的对象是在堆上面分配的。如果这两行语句出现在一个函数内部,意味着当函数结束时,pObj会被销毁,但是它指向的对象不会。因此,为了继续使用这个对象,通常我们会在函数最后添加一个return语句,或者使用一个传出参数。否则的话,这个在堆上创建的对象就没有指针指向它,也就是说,这个对象造成了内存泄露。

并不是说指针指向的对象都是在堆上创建的。下面的代码则使用指针指向一个在栈上创建的对象:

 

至此,我们解释了函数内部的变量和成员变量。还有两类变量:全局变量和static变量。它们即不在堆上创建,也不在栈上创建。它们有自己的内存空间,是除堆和栈以外的数据区。也就是说,当Object obj即不在函数内部,又不是类的成员变量时,这个对象会在全局数据段创建,同理适用于static变量。对于指针Object *pObj;,如果这个语句出现在函数内部或类的成员变量,正如我们前面所说的,这个指针是自动存储的。但是,如果这个语句是在类的外部,它就是在全局数据段创建的。虽然它指向的对象可能在堆上创建,也可能在栈上创建。

堆和栈的区别在于两点:

  1. 生命周期
  2. 性能

第一点才是我们需要着重考虑的。由于栈的特性,如果你需要一个具有比其所在的上下文更长的生命周期的变量,只能在堆上创建它。所以,我们的推荐是:只要能在栈上创建对象,就在栈上创建;否则的话,如果你不得不需要更长的生命周期,只能选择堆上创建。这是由于在栈上的对象不需要我们手动管理内存。有经验的开发人员都会对内存管理感到头疼,我们就是要避免这种情况的发生。总的来说,我们更多推荐选择在栈上创建对象。

但是,有些情况,即便你在栈上创建了对象,它还是会占用堆的空间。考虑如下代码:

 

 

对象v是在栈上创建的。但是,STL 的vector类其实是在堆上面存储数据的(这点可以查看源代码)。因此,只有对象v本身是在栈上的,它所管理的数据(这些数据大多数时候都会远大于其本身的大小)还是保存在堆上。

关于第二点性能,有影响,不过一般可以忽略不计。确切的说,一般情况下你不需要考虑性能问题,除非它真的是一个问题。

首先,在堆上创建对象需要追踪内存的可用区域。这个算法是由操作系统提供,通常不会是常量时间的。当内存出现大量碎片,或者几乎用到 100% 内存时,这个过程会变得更久。与此相比,栈分配是常量时间的。其次,栈的大小是固定的,并且远小于堆的大小。所以,如果你需要分配很大的对象,或者很多很多小对象,一般而言,堆是更好的选择。如果你分配的对象大小超出栈的大小,通常会抛出一个异常。尽管很罕见,但是有时候也的确会发生。有关性能方面的问题,更多出现在嵌入式开发中:频繁地分配、释放内存可能造成碎片问题。

现代操作系统中,堆和栈都可以映射到虚拟内存中。在 32 位 Linux,我们可以把一个 2G 的数据放入堆中,而在 Mac OS 中,栈可能会限制为 65M。

总的来说,关于究竟在堆上,还是在栈上创建对象,首要考虑你所需要的生命周期。当性能真正成为瓶颈的时候,才去考虑性能的问题。堆和栈是提供给开发者的两个不同的工具,不存在一个放之四海而皆准的规则告诉你,一个对象必须放在堆中还是在栈中。选择权在开发者手中,决定权在开发者的经验中。

分享到:
评论

相关推荐

    c++如何控制对象的创建方式(禁止创建栈对象or堆对象)和创建的数量

    禁止创建栈对象,意味着只能在堆上创建对象。创建栈对象时会移动栈顶指针以“挪出”适当大小的空间,然后在这个空间上直接调用类的构造函数以形成一个栈对象。而当栈对象生命周期结束,如栈对象所在函数返回时,会...

    Java创建对象与C++创建对象的比较

     1、C++创建对象方式  在C++中我们可以采用如下两种方式来创建对象, 1 Dog dog;//Dog为类名 2 Dog *p = new Dog();  这两种方式在C++中都能完成对象的创建,但是在内存中的处理却完全不同。  对于...

    C++用new创建对象和不用new创建对象的区别解析

    我们都知道C++中有三种创建对象的方法,如下: 代码如下:#include <iostream>using namespace std; class A{private: int n;public: A(int m):n(m) { } ~A(){}}; int main(){ A a(1); //栈中分配 A b = A(1)...

    栈类模板C++代码

    编写一个栈的类模板(包括其成员函数定义),以便为任何类型的对象提供栈结构数据操作。并在应用程序中创建整数栈、字符栈和浮点数栈,提供一些数据进行进栈、退栈和打印操作的测试。

    编程狂人第十三期

    C++:在堆上创建对象,还是在栈上? 技术纵横 UPYUN:用Erlang开发的对象存储系统 iOS 7最佳实践:一个天气App案例 看看百度招iOS开发面试的问题,你能答对多少? CoconutKit:iOS开发必备的开源组件库 Associated ...

    设计一个只能在堆上或栈上实例化的类

    一道C++笔试题:设计一个只能在堆内存上实例化的类和一个只能在栈内存上实例化的类  只能在堆内存上实例化的类:将析构函数定义为private,在栈上不能自动调用析构函数,只能手动调用。也可以将构造函数定义为...

    c++ 入门 构造函数 时间类

    问题描述: 编写时间类 要求: 1)严格遵守编码规范。 2)构造函数采用带初始化列表的...另分别在栈区、堆区、全局区再分别创建三个对象(创建对象时提供参数) 6)运行效果不做硬性要求,仅看重编码规范及类的设计!

    [java]读书笔记整理:一切都是对象

    用堆进行存储分配比用堆栈进行存储分配需要更多的时间(如果确实可以在java中向在C++中一样在栈中创建对象)。 4) 静态存储 这里的“静态”是指“在固定的位置”(尽管也在RAM里)。静态存储里存放程序运行时一直...

    零起点学通C++多媒体范例教学代码

    8.4.2 在堆中创建对象 8.4.3 在堆中删除对象 8.4.4 访问堆中的数据成员 8.4..5 在构造函数中开辟内存空间 8.4.6 对象在栈与堆中的不同 8.5 this指针 8.6 指针的常见错误 8.7 指针运算 8.7.1 指针的加减运算 8.7.2 ...

    新手学习C++入门资料

    在当时,面向对象编程还是一个比较新的理念,Stroustrup博士并不是从头开始设计新语言,而是在C语言的基础上进行创建。这就是C++语言。 1985年,C++开始在外面慢慢流行。经过多年的发展,C++已经有了多个版本。为次...

    零起点学通C++学习_多媒体范例教学代码

    8.4.2 在堆中创建对象 8.4.3 在堆中删除对象 8.4.4 访问堆中的数据成员 8.4..5 在构造函数中开辟内存空间 8.4.6 对象在栈与堆中的不同 8.5 this指针 8.6 指针的常见错误 8.7 指针运算 8.7.1 指针的加减运算 ...

    C++和面向对象数值计算

    10.2.3 集合、排列和堆算法 10.3 标准函数对象和适配器 10.3.1 算术函数对象 1o.3.2 关系函数对象 10.3.3 逻辑函数对象 10.3.4 标准适配器 10.4 练习 第11章 线性方程组求解法 11.1 矩阵存储...

    C++智能指针(1).pdf

    智能指针主要⽤于管理在堆上分配的内存,它将普通的指针封装为⼀个栈对象。当栈对象的⽣存周期结束后,会在析构函数中释放掉申请的 内存,从⽽防⽌内存泄漏。简要的说,智能指针利⽤了 C++ 的 RAII 机制,在智能...

    C++智能指针的原理和实现.pdf

    如果对象是⽤声明的⽅式在栈上创建局部对象,那么RAII机制就会正常⼯作,当离开作⽤域对象会⾃动销毁⽽调⽤析构函数释放资 源。 ⼆、智能指针类型 ⼆、智能指针类型 智能指针在C++11版本之后提供,包含在头⽂件中,...

    QT学习之路2 (1~82篇)

    详细目录 1. 序 2. Qt 简介 3. Hello, world! 4. 信号槽 5. 自定义信号槽 6. Qt 模块简介 7. MainWindow 简介 8. 添加动作 9. 资源文件 10. 对象模型 11. 布局管理器 ...C++:在堆上创建对象,还是在栈上?

    C++ Primer第四版【中文高清扫描版】.pdf

    3.5.2 bitset对象上的操作 90 小结 92 术语 92 第4章 数组和指针 95 4.1 数组 96 4.1.1 数组的定义和初始化 96 4.1.2 数组操作 99 4.2 指针的引入 100 4.2.1 什么是指针 100 4.2.2 指针的定义和初始化 101 4.2.3 ...

    Cocos2d-x开发中C++内存管理

     创建对象须要两个步骤:第一步,为对象分配内存,第二步,调用构造函数初始化内存。在第一步中对象分配内存时候,我们能够选择几个不同的分配区域,这几个区域例如以下:  栈区域分配。栈内存分配运算内置于...

    C++智能指针详解.pdf

    ⼆、具体使⽤ 1、总括 对于编译器来说,智能指针实际上是⼀个栈对象,并⾮指针类型,在栈对象⽣命期即将结束时,智能指针通过析构函数释放有它管理的 堆内存。所有智能指针都重载了"operator->"操作符,直接返回...

    c++中堆栈及创建对象示例代码

    堆(heap),堆包含一个链表来维护已用和空闲的不连续的内存块,存放在二级缓存中,一般由程序员分配释放。 快速记忆方式: 一级缓存比二级缓存快,栈是一个先进后出列表,存取非常快,所以栈是在一级缓存中。 栈中...

Global site tag (gtag.js) - Google Analytics