这种类型的内存是在堆还是栈上分配的?

Posted

技术标签:

【中文标题】这种类型的内存是在堆还是栈上分配的?【英文标题】: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;

然后在堆栈上创建它。

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

【问题讨论】:

【参考方案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 种类型的“存储持续时间”,但没有明确说明必须如何实现存储:

    静态存储时长 自动存储时长 动态存储时长

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

动态存储持续时间通常使用堆实现(最终通过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 执行此操作,它将作为对象的一部分在堆上。

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

【讨论】:

也许他在问语言规范的哪一部分是这样说的 :-)

以上是关于这种类型的内存是在堆还是栈上分配的?的主要内容,如果未能解决你的问题,请参考以下文章

对象的私有成员是在堆上还是在栈上?

Java内存分配机制

Go 语言中的变量究竟是分配在栈上还是分配在堆上?

Go 语言中的变量究竟是分配在栈上还是分配在堆上?

字符串类型是存储在堆上还是栈上?

内存分配