65

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

Object o;

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

Object* o;

o = new Object();

而不是:

Object* o = new Object();

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

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

4

7 回答 7

128

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

Object o;

根据其上下文创建以下内容之一:

  • 具有自动存储功能的局部变量,
  • 命名空间或文件范围内的静态变量,
  • 指定另一个对象的子对象的成员变量。

这意味着存储位置由定义对象的上下文确定。此外,C++ 标准没有讨论堆栈堆存储。相反,它谈论存储持续时间,它可以是自动的、动态的、静态的或线程本地的。然而,大多数实现通过调用栈实现自动存储,通过堆实现动态存储。

因此,在堆栈上创建了具有自动存储功能的局部变量。静态(和线程本地)对象通常分配在它们自己的内存区域中,既不在堆栈上,也不在堆上。并且在分配它们所属的对象的任何地方分配成员变量。它们有其包含对象的存储期限。

用一个例子来说明这一点:

struct Foo {
    Object o;
};

Foo foo;

int main() {
    Foo f;
    Foo* p = new Foo;
    Foo* pf = &f;
}

现在对象Foo::o(即oclass 对象的子对象Foo)在哪里创建?这取决于:

  • foo.o具有静态存储,因为foo具有静态存储,因此既不在堆栈上也不在堆上。
  • f.o具有自动存储,因为f具有自动存储(= 它存在于堆栈中)。
  • p->o具有动态存储,因为*p具有动态存储(=它位于堆上)。
  • pf->o是同一个对象,f.o因为pf指向f

其实ppf上面都有自动存储。指针的存储与任何其他对象的存储没有区别,它由上下文决定。此外,初始化表达式对指针存储没有影响。

指针(=指针指向的内容)是完全不同的事情,可以指任何类型的存储:*p是动态的,而是*pf自动的。

于 2012-04-14T20:42:59.457 回答
14

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

  1. 基于堆栈的,例如临时对象
  2. 使用新的基于堆的
  3. 静态内存分配,例如全局变量和命名空间范围对象

考虑你的情况,

Object* o;
o = new Object();

和:

Object* o = new Object();

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

于 2014-11-06T10:11:06.650 回答
6

C++ 有自动变量 - 而不是堆栈变量。

自动变量意味着 C++ 编译器自己处理内存分配/释放。C++ 可以自动处理任何类的对象——无论它是否具有动态分配的成员。这是通过 C++ 的强大保证来实现的,即当执行超出声明自动变量的范围时,将自动调用对象的析构函数。C++ 对象内部可以有很多new在构造函数中的动态分配,当这样的对象被声明为自动变量时 - 所有动态分配都将被执行,然后在析构函数中释放。

C 中的堆栈变量不能动态分配。C 中的堆栈可以存储指针、固定数组或结构——所有这些都是固定大小的,这些东西在内存中以线性顺序分配。当 C 程序释放堆栈变量时 - 它只是将堆栈指针移回,仅此而已。

即使 C++ 程序可以使用堆栈内存段来存储原始类型、函数的 args 或其他 - 这一切都是由 C++ 编译器决定的,而不是由程序开发人员决定的。因此,将 C++ 自动变量和 C 堆栈变量相等在概念上是错误的。

于 2019-09-24T21:29:57.177 回答
5

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

于 2012-04-14T20:36:44.513 回答
1

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

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

这是一个讨论正在运行的 C 程序的内存布局的链接。

于 2012-04-14T20:42:29.387 回答
1

一种)

Object* o;
o = new Object();

`` B)

Object* o = new Object();

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

我想提一提的是,从堆中分配的内存大小始终是 sizeof(Object) 而不是 sizeof(Object) + sizeof(void *)。

于 2012-04-15T12:59:54.647 回答
-2
  1. 对象* o; o = 新对象();

  2. 对象* o = 新对象();

这两个语句都在堆内存中创建对象,因为您使用“new”创建对象。

为了能够在堆栈中创建对象,您需要遵循以下步骤:

Object o;
Object *p = &o;
于 2020-07-25T21:42:42.150 回答