堆与堆栈分配

Heap vs Stack allocation

本文关键字:分配 堆栈      更新时间:2023-10-16

我对在堆上分配对象和在堆栈上分配对象的主题有点困惑,以及何时以及如何调用delete()。

例如,我有一个类Vector。我想把它们组成一个数组。

我可以这样做

Vector** v = new Vector*[100]; //create an array of 100 pointers to 100 Vector objects

据我所知,这将在堆上分配一切(除了指针地址)?因此,为了释放内存,我需要:

for (int i = 0; i < 100; ++i)
{
   delete(v[i]);
}
delete(v);

还是

delete(v);

是足够了吗?

现在再看一个例子:

Vector* v = Vector[100];

在这种情况下发生了什么?分配发生在哪里?堆还是堆栈?我还需要打电话吗?

delete(v);

但这并不是所有的问题,抱歉写了这么长时间。

的例子:

class Vector
{
  int x, y, z;
}
Vector* v = new Vector();

,其中x, y, z分配?堆还是堆栈?

或者

class Vector2
{
   int items[10];
}
Vector2* v2 = new Vector2();

项[10]在哪里分配?如何删除v2?我需要自定义析构函数吗?

最后但并非最不重要的是这个如何:

class Vector3
{
   int* items;
}
Vector3 v3 = Vector3();

项目指针存储在哪里?堆还是堆栈?我如何删除这个?

谢谢,很抱歉长时间的问题。我一直有这个问题很长一段时间,不能找到任何完整的解释在网上。

我将从头开始…

Vector** v = new Vector*[100];

分配一个包含100个指针的数组,指向堆上Vector类型的对象它返回一个指针——v——你可以用它来跟踪这个指针数组。

删除100个点的数组:

delete[] v;

(使用delete运算符- delete用于单个已分配对象,delete[]用于数组)

下一种情况(我假设你是指new Vector[100]:

)
Vector* v = new Vector[100];

你在堆上分配了一个包含100个vector的数组,并获得了一个指向其起始位置的指针——v。用

删除这个数组
delete[] v;
下…

class Vector
{
  int x, y, z;
}
Vector* v = new Vector();

在堆上分配一个Vector类的对象,并给你一个指针来跟踪它。因为您在堆上分配了整个对象,所以x、y和z都在堆上分配。

删除:

delete v;

class Vector2
{
   int items[10];
}
Vector2* v2 = new Vector2();

这个有点棘手,但我要推理出来…

类是蓝图。在以某种方式实例化类(在本例中是在堆上)之前,您根本没有分配任何内存。因为这个类是一个蓝图,所以在堆上创建Vector2类的对象之前,不能分配items。我认为我们可以合理地推断,items因此被分配在堆上。

Delete v2 with:

delete v2;

最后:

class Vector3
{
   int* items;
}
Vector3 v3 = Vector3();

你在堆栈上分配了所有的Vector3类,它里面的指针items也被分配了。堆上没有任何东西,所以不要删除它。

让我们注意到你可能不需要动态分配任何东西。
静态数组或vector都可以更好地工作。

但是让我们假设你正在做一个学习练习。

1分配指针数组

Vector** v = new Vector*[100]; //create an array of 100 pointers to 100 Vector objects
                               //
                               // The above comment is misleading.
                               // The 100 pointers have not been initialized.

这为100个指针分配了一块内存空间(指向Vector(注意它们是未初始化的,即每个指针都是随机的))。要删除它,您需要执行以下命令:

delete [] v;

2分配数组

的成员

如果你分配了每个成员(如果你想使用它们,你应该这样做):

for (int i = 0; i < 100; ++i)
{
   v[i] = new Vector;
}
// Code
for (int i = 0; i < 100; ++i)
{
   delete v[i];
}

因此,请注意,对于每个new调用都应该有一个相应的delete调用。

3 An ERROR

Vector* v = Vector[100];

这是错误的。

4成员去哪里

除非该成员是指针,否则它位于对象内部。
如果成员是指针,则必须单独分配。

class Vector
{
  int x, y, z;
}
Vector* v1 = new Vector();
Vector  v2 = Vector();      // Yes the = Vector() is required

v1指向包含x/y/z的动态分配对象
这里v2是一个包含x/y/z

的对象

我知道人们会说= Vector();是一个不需要的或复制结构。都是对的,但都没有抓住重点。1)这是一个复制结构,但编译器总是足够聪明地删除它。2)需要使其与上面的行等效。不同之处在于没有它是default-initialized(即未初始化),它的成员是zero-initialized(因为Vector()只有一个编译器生成的构造函数)。

那么数组成员呢?
他们和其他成员没有什么不同。成员在对象内部分配ALWAYS。如果成员是指针,则它位于对象内部,但必须显式设置它所指向的对象。

class Bob
{
    int   dataArray[10];
    int*   dataPtr;
};
Bob  b1 = Bob();
Bob* b2 = new Bob();
b1.dataArray[0] = 1;            // dataArray is inside the object.
                                // b1 is allocated locally
b1.dataPtr      = new int [10]; // dataPtr is inside the object.
                                // But what it points at must be seprotally defined.
                                // Note you must call delete [] for each new []
b1.dataPtr[5] = 2;
b2->dataArray[0] = 1;           // dataArray is inside the object.
                                // b2 is allocated dynamically
b2->dataPtr      = new int [10];// dataPtr is inside the object.
                                // But what it points at must be aseptically defined.
                                // Note you must call delete [] for each new []
b2->dataPtr[5] = 2;

一般规则:

  • 当你使用newnew []时,你在堆上分配,在其他情况下,你在堆栈上分配。

  • 每次你使用new,你应该使用delete(显式或不显式)

  • 每次你使用new[],你应该使用delete[](明确或不明确)

下一个代码是UB,因为您使用了一个new[]和101 delete。使用一个delete[]

Vector** v = new Vector*[100];
for (int i = 0; i < 100; ++i)
{
   delete(v[i]);
}
delete(v);
  1. delete [] v; -它是delete操作符的数组表示法。你必须在删除数组时使用它,而不是依次删除每个元素。
  2. Vector* v = Vector[100];无法编译。写入Vector v[100];,它将在堆栈上分配向量数组。您不能手动删除它。
  3. x, y, z在堆上,因为整个对象在堆上
  4. items[10]也在堆上分配,因为它是对象的一部分。要删除它,只需调用delete v2;。你不需要一个特殊的析构函数,除非你在构造函数中分配任何东西。
  5. int* items;被存储在堆栈上,因为它是堆栈上分配的对象的一部分。您不必删除它,当超出作用域时,它将被自动删除。