堆与堆栈分配
Heap vs Stack allocation
我对在堆上分配对象和在堆栈上分配对象的主题有点困惑,以及何时以及如何调用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;
一般规则:
-
当你使用
new
或new []
时,你在堆上分配,在其他情况下,你在堆栈上分配。 -
每次你使用
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);
-
delete [] v;
-它是delete操作符的数组表示法。你必须在删除数组时使用它,而不是依次删除每个元素。 -
Vector* v = Vector[100];
无法编译。写入Vector v[100];
,它将在堆栈上分配向量数组。您不能手动删除它。 -
x, y, z
在堆上,因为整个对象在堆上 -
items[10]
也在堆上分配,因为它是对象的一部分。要删除它,只需调用delete v2;
。你不需要一个特殊的析构函数,除非你在构造函数中分配任何东西。 -
int* items;
被存储在堆栈上,因为它是堆栈上分配的对象的一部分。您不必删除它,当超出作用域时,它将被自动删除。
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 从堆栈分配的原始指针构造智能指针
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 巨大的内存分配:堆栈与堆
- 有效地分配堆栈对象(由函数的值返回)到堆?
- 为什么不能在 Visual C++ 中动态分配堆栈内存?但海湾合作委员会可以做到
- 为什么分配堆内存比分配堆栈记忆更快
- 安全分配堆栈分配的阵列
- 附加到具有非动态分配堆栈的向量
- 是否随作用域分配和解除分配堆栈帧
- 在执行中脱离堆栈对象的范围之前,请分配堆栈对象
- 全局阵列分配 -- 堆栈或堆
- 如何使新操作员超载以分配堆栈
- 具有类作用域的动态分配堆栈内存
- 如何在 Linux 下为可执行文件分配堆栈
- 内存分配堆栈
- 成员函数内存分配堆栈或堆
- 在 c++ 中重新分配堆栈上的对象
- 防止为类和派生类分配堆栈
- 如何防止msvc++为switch语句过度分配堆栈空间?