【问题标题】:Does this type of memory get allocated on the heap or the stack?这种类型的内存是在堆还是栈上分配的?
【发布时间】:2010-09-30 09:59:27
【问题描述】:

在 C++ 的上下文中(没关系):

class Foo{
    private:
        int x[100];
    public:
        Foo();
}

我所学到的告诉我,如果你像这样创建一个 Foo 的实例:

Foo bar = new Foo();

那么数组 x 是在堆上分配的,但是如果你像这样创建了一个 Foo 的实例:

Foo bar;

然后在堆栈上创建它。

我在网上找不到资源来确认这一点。

【问题讨论】:

    标签: c++ memory-management stack heap-memory


    【解决方案1】:

    是的,如果您在堆上创建Foo 对象,则会在堆上创建成员数组x。当您为Foo 分配动态内存时,您要求的内存长度为sizeof(Foo)(可能还有一些内存开销,但我们暂时忽略它),这在您的示例代码中意味着100 ints 的大小.这必须Foo 类型的对象(及其内部数据)的生命周期内跨越范围。

    如果您不在堆上创建Foo 对象,并且Foo 的内部数组不是您在Foo 的构造函数中使用new 分配内存的指针,那么内部数组将在堆栈上创建。同样,为了在范围结束时自动清理阵列而没有任何deletes,必须是这种情况。具体来说,

    struct Foo {
        int* y;
        Foo() : y(new int()) { }
        ~Foo() { delete y; }
    };
    

    将在堆上创建y,无论Foo 对象是在堆栈上还是在堆上创建。

    【讨论】:

      【解决方案2】:

      严格来说,根据标准,对象不必存在于堆栈或堆中。该标准定义了 3 种类型的“存储持续时间”,但没有明确说明必须如何实现存储:

      1. 静态存储时长
      2. 自动存储时长
      3. 动态存储时长

      自动存储持续时间通常(几乎总是)使用堆栈实现。

      动态存储持续时间通常使用堆实现(最终通过malloc()),但即使编译器的用户也可以覆盖它。

      静态存储持续时间通常称为全局变量(或静态存储)。

      标准对这些事情有这样的说法(以下是 3.7 - Storage Duration 的各个部分的摘录):

      静态和自动存储期限 与引入的对象相关联 通过声明(3.1)和隐式 由实现(12.2)创建。 动态存储时长为 与创建的对象相关联 新运算符 (5.3.4)。

      ...

      所有没有动态的对象 存储期限也没有本地有 静态存储时间。存储 对于这些对象应持续 计划的持续时间(3.6.2, 3.6.3)。

      ...

      本地对象显式声明为 auto 或注册或未明确声明 静态或外部有自动 储存期限。存储为 这些对象持续到块 它们被创建的出口。

      ...

      对象可以动态创建 在程序执行期间(1.9),使用 新表达式(5.3.4),并销毁 使用删除表达式 (5.3.5)。交流电 + + 实现通过以下方式提供对动态存储的访问和管理 全局分配函数 运算符 new 和 operator new[] 和 全局释放函数 运算符删除和运算符删除[]。

      ...

      库提供默认 全局分配的定义 和释放功能。一些 全局分配和释放 功能可替换 (18.4.1)

      最后(关于示例类中的数组):

      3.7.4 子对象的持续时间 [basic.stc.inherit]

      成员子对象、基类子对象和数组元素的存储时长是它们完整的存储时长 对象 (1.8)。

      【讨论】:

        【解决方案3】:

        对您的示例稍作修改:

        class Foo{
            private:
                int x[100];
                int *y;
            public:
                Foo()
                {
                   y = new int[100];
                }
                ~Foo()
                { 
                   delete[] y; 
                }
        
        }
        

        示例 1:

        Foo *bar = new Foo();
        
        • x 和 y 在堆上:
        • sizeof(Foo*) 在堆栈上创建。
        • sizeof(int) * 100 * 2 + sizeof(int *) 在堆上

        示例 2:

        Foo bar;
        
        • x 在栈上,y 在堆上
        • sizeof(int) * 100 在栈上 (x) + sizeof(int*)
        • sizeof(int) * 100 在堆上 (y)

        实际大小可能会因类/结构对齐而略有不同,具体取决于您的编译器和平台。

        【讨论】:

        • 您对如何得出结论有任何建议的参考资料吗?我的印象与 OP 相同;调用new 会在堆上为数据动态分配内存。否则,像Foo bar 这样的调用会将本地数据压入堆栈。无论哪种情况,我都希望类指针严格分配在堆栈上。修饰符publicprivate对分配方式有何影响?
        【解决方案4】:

        你是说

        Foo* bar = new Foo(); 
        

        我想。 那个是在堆中创建的。

        【讨论】:

          【解决方案5】:

          Foo 类型的对象按顺序存储 100 个整数。 如果你在堆栈上创建它,你将把它全部放在堆栈上。 如果您使用 new 执行此操作,它将作为对象的一部分在堆上。

          这是语言规范的一部分,我不确定您的问题是什么。

          【讨论】:

          • 也许他在问语言规范的哪一部分是这样说的 :-)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-04-23
          • 2012-07-29
          • 2018-02-04
          • 2014-11-02
          • 2013-10-29
          • 2014-04-01
          • 2021-10-04
          相关资源
          最近更新 更多