在堆栈/堆上创建对象

Object creation on the stack/heap?

本文关键字:创建对象 堆栈      更新时间:2023-10-16

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

Object o;

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

Object* o;
o = new Object();

而不是:

Object* o = new Object();

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

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

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

Object o;

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

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

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

因此,在堆栈上创建具有自动存储的局部变量。静态(和线程本地)对象通常分配在它们自己的内存区域中,既不在堆栈上也不在堆上。成员变量在分配它们所属的对象的任何位置进行分配。它们具有其包含对象的存储持续时间。

举个例子来说明这一点:

struct Foo {
    Object o;
};
Foo foo;
int main() {
    Foo f;
    Foo* p = new Foo;
    Foo* pf = &f;
}

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

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

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

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

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

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

考虑你的情况,

Object* o;
o = new Object();

和:

Object* o = new Object();

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

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

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

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

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

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

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

全局变量的内存区域

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

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

A)

Object* o;
o = new Object();

''二)

Object* o = new Object();

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

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

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

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

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

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

Object o;
Object *p = &o;