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

4

在C++的背景下(这并不重要):

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

我了解到,如果你像这样创建Foo的实例:

Foo bar = new Foo();

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

Foo bar;

然后它被创建在堆栈上。

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

5个回答

10
严格来讲,按照标准,对象不需要存在于堆栈或堆上。标准定义了3种“存储期”,但并未明确规定存储必须如何实现:
  1. 静态存储期
  2. 自动存储期
  3. 动态存储期
自动存储期通常(几乎总是)使用堆栈来实现。
动态存储期通常使用堆来实现(最终通过malloc()),尽管编译器的用户可以覆盖这一点。
静态存储期通常称为全局变量(或静态存储)。
标准对这些内容有如下说明(以下是从3.7 - 存储期的各个部分摘录的):

静态存储期和自动存储期与引入声明(3.1)或由实现隐含创建(12.2)的对象相关联。动态存储期与使用new运算符(5.3.4)创建的对象相关联。

...

既没有动态存储期也不是本地对象的所有对象都具有静态存储期。这些对象的存储期将持续整个程序的执行时间(3.6.2、3.6.3)。

...

明确声明为自动或寄存器,或未明确声明为静态或外部的本地对象具有自动存储期。这些对象的存储期将持续到它们被创建的块退出。

...

可以在程序执行过程中使用new表达式(5.3.4)动态创建对象,并使用delete表达式(5.3.5)销毁对象。C++实现通过全局分配函数operator new和operator new[]以及全局释放函数operator delete和operator delete[]提供对动态存储的访问和管理。

...

标准库提供了默认的实现,如std::allocator类、std::unique_ptr和std::shared_ptr模板来管理动态内存。

全局分配和释放函数的定义。一些全局分配和释放函数是可替换的(18.4.1)。
最后(关于你示例类中的数组):
3.7.4 子对象的存储期 [basic.stc.inherit]
成员子对象、基类子对象和数组元素的存储期是它们所属的完整对象的存储期(1.8)。

10

假设你的示例稍作修改:

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 *)位于堆上。
Foo bar;
  • x在栈上,而y在堆上
  • sizeof(int) * 100位于栈上(x)+ sizeof(int *)
  • sizeof(int) * 100位于堆上(y)

由于编译器和平台的类/结构对齐方式不同,实际大小可能略有差异。


1
你有什么建议的参考资料来支持你的结论吗?我也和 OP 有同样的印象;调用 new 动态地为数据在堆上分配内存。否则,像 Foo bar 这样的调用会将本地数据推入堆栈。无论哪种情况,我都希望类指针严格分配在堆栈上。修饰符 publicprivate 如何影响分配方法? - sherrellbc

7

类型为Foo的对象占用了100个按顺序存储的int的大小。如果你在堆栈上创建它,你将会把所有东西都放在堆栈上。如果你使用new来创建它,它将作为对象的一部分存在于堆中。

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


也许他在问语言规范的哪个部分表明了这一点 :-) - PolyThinker

2
是的,如果你在堆上创建Foo对象,那么成员数组x将在堆上创建。当你为Foo分配动态内存时,你正在请求长度为sizeof(Foo)的内存(加上可能的一些内存开销,但让我们在此忽略这一点),在你的示例代码中,这意味着100个int的大小。为了使类型为Foo的对象(及其内部数据)跨范围存在,必须这样做。
如果你没有在堆上创建Foo对象,且Foo的内部数组不是指向在Foo构造函数中使用new分配的内存的指针,则该内部数组将在堆栈上创建。同样,为了使数组在作用域结束时自动清除而无需任何delete,必须这样做。具体来说,
struct Foo {
    int* y;
    Foo() : y(new int()) { }
    ~Foo() { delete y; }
};

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


1

你的意思是

Foo* bar = new Foo(); 

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接