关于c ++:堆栈/堆上的对象创建?

Object creation on the stack/heap?

以下代码在堆栈上创建一个对象:

1
Object o;

在堆上创建对象时,我们可以使用:

1
2
3
Object* o;

o = new Object();

而不是:

1
Object* o = new Object();

当我们将堆对象创建拆分为两行并在第二行(o = new object()调用构造函数)时,这是否意味着在第一行(Object* o中,指针是在堆栈上创建的?那么,Object o把对象放在栈上,而Object* o把指向栈上未来对象的指针放在栈上?

我的第二个问题涉及两行代码是否在类外调用。我最近读到(堆栈或堆中的C中的全局内存管理?)全局变量不包含在堆栈/堆中,但实际上是内存的另一部分?如果是这种情况,Object* o是否会创建一个指针,该指针将位于内存的另一部分,并指向堆对象?


实际上,这两个语句都没有提到堆或堆栈:

1
Object o;

创建一个具有自动存储的对象,这意味着存储位置由声明该对象的上下文决定:如果代码在函数中,这恰好是调用堆栈。但是行也可以是类成员,或者如您所注意到的,在函数/类之外。

为了说明这不同的原因:

1
2
3
4
5
struct Foo {
    Object o;
};

Foo* pf = new Foo();

现在,对象pf->o是在堆上创建的,而不是在堆栈上创建的,即使(或者更确切地说,因为)它有自动存储。

相反地,

1
Object* p;

只声明一个指针,不需要更多。指针的存储与任何其他对象的不可区分:它有自动存储。此外,初始化表达式对变量存储没有影响。

指针指向的是一个完全不同的问题。它可能是一个堆分配的对象(例如使用new),也可能指向另一个自动分配的对象。考虑:

1
2
Object o;
Object* p = &o;


C++提供了三种不同的创建对象的方法:

  • 基于堆栈,如临时对象
  • 使用new基于堆
  • 静态内存分配,如全局变量和命名空间范围对象
  • 考虑一下你的情况,

    1
    2
    Object* o;
    o = new Object();

    还有:

    1
    Object* o = new Object();

    两种形式相同。这意味着在堆栈上创建了一个指针变量O(假设您的变量不属于上面的3个类别),它指向包含对象的堆中的内存。


    两种形式相同,但有一个例外:临时情况下,当创建和分配分开时,新的(Object *)具有未定义的值。编译器可以将它们组合在一起,因为未定义的指针不是特别有用。这与全局变量无关(除非声明是全局的,在这种情况下,两种形式的声明都是正确的)。


    a)

    1
    2
    Object* o;
    o = new Object();

    ` `B)

    1
    Object* o = new Object();

    我认为A和B没有区别。在这两种情况下,o都是指向类对象的指针。语句new object()从堆内存创建类对象的对象。赋值语句将分配内存的地址分配给指针O。

    我想说的是,从堆中分配的内存的大小始终是size of(object),而不是sizeof(object)+sizeof(void*)。


    在这两个示例中,Object*类型的局部变量都在堆栈上分配。如果您的程序无法检测到差异,编译器可以从两个代码片段中自由地生成相同的代码。

    全局变量的内存区域与静态变量的内存区域相同-既不在堆栈上也不在堆上。您可以通过在函数内部声明static来将变量放置在该区域中。这样做的结果是,实例在您的函数的并发调用之间成为共享的,所以在使用statics时需要仔细考虑同步。

    下面是一个链接,指向正在运行的C程序内存布局的讨论。