zoukankan      html  css  js  c++  java
  • 【转】C++对象是创建在堆上,还是在栈上?

    https://blog.csdn.net/Solo_two/article/details/79780086

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

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

    Object obj;

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

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

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

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

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

    class Class
    {
        Object obj;
    };
     
    Class *pClass = new Class;

      // 指针pClass所指向的对象在堆上分配空间。

      // 因为Object obj;语句的含义是“自动存储”,所以,pClass->obj也是在堆上创建的。

    Object *pObj;
    pObj = new Object;
    // Object *pObj;代表,指针pObj是自动存储
    // 仅此而已,没有任何其它含义。
    // 而之后一行语句则指出,这个指针所指向的对象是在堆上面分配的。

    如果这两行语句出现在一个函数内部,意味着当函数结束时,pObj会被销毁,但是它指向的对象不会。因此,为了继续使用这个对象,通常我们会在函数最后添加一个return语句,或者使用一个传出参数。否则的话,这个在堆上创建的对象就没有指针指向它,也就是说,这个对象造成了内存泄露

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

    Object obj;
    Object *pObj = &obj;

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

    堆和栈的区别在于两点:

    1. 生命周期
    2. 性能

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

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

    void func
    {
        std::vector v;
    }

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

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

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

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

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

  • 相关阅读:
    Python 3学习 ——目录 Json Pickle
    Python 3 学习——函数扩展and迭代器生成器装饰器
    Python 3 学习——深浅拷贝以及函数
    Python 3 学习的第七小节——Linux-Ubuntu
    Python 3 —— 文件操作
    Python 3 学习的第五小节——字符编码与三级菜单实践
    关于PHP代码复用‘traits’的一段代码
    一个将对象彻底冻结的函数
    详解vue-cli脚手架项目-package.json
    关于element-ui日期选择器disabledDate使用心得
  • 原文地址:https://www.cnblogs.com/qxxnxxFight/p/11137309.html
Copyright © 2011-2022 走看看