我正在(重新)学习C ++(再次经历了Java和Python的多年之后),但似乎我对堆栈和堆栈的概念已经不熟悉了。我正在读这样的线程,这很清楚:函数/方法中的局部变量存在于堆栈中,并且在离开该函数/方法时将被销毁。对于需要更长时间的对象,我需要在堆上分配内存。
美好的。但不是我正在阅读一些C ++代码并看到以下内容(简化):
struct MyStruct
{
int Integer;
bool Boolean;
}
// in header file
class MyClass
{
TArray<MyStruct> MyArray; // TArray is a custom dynamic array in the framework
void FillArray();
TArray<MyStruct> GetArray() { return MyArray; }
}
// in cpp file
void MyClass::FillArray()
{
for(int i = 0; i < 10; ++i)
{
MyStruct s; // These objects are created on the stack, right?
s.Integer = i;
s.Boolean = true;
MyArray.Add(s);
}
}
因此,有一个自定义结构MyStruct
,以及一个具有容器的类MyArray
。然后在某个时候我调用MyClass->FillArray()
初始化数组。在那种方法中,我MyStruct
在堆栈上创建了对象(即不是通过new
),并将它们添加到数组中。据我了解,FillArray()
方法返回后应立即销毁数组中的这些对象。
现在稍后在代码中调用MyClass->GetArray()
。令我惊讶的是,返回的数组确实包含了以前创建的所有struct对象。
为什么这些struct对象仍然存在,为什么在FillArray()
方法返回后不立即销毁它们呢?
Matthias,您似乎已经足够正确地理解了“堆栈”和“堆”变量的概念。您错过的“魔术”是MyArray::Add
克隆提供的s,因此其值保留在MyArray实例中。
如果您发现“ stack-”变量是神秘的,只需将它们视为任何作用域变量。当范围变量超出范围时,它会被破坏。函数的局部变量只是作用域的一种特殊情况。
要使数据“存在”范围之外,您需要在堆上创建数据(使用new
),然后按值传递指向其位置的指针。如果要在线程之间共享数据,也是如此。另一个执行线程只是使用其自身的调用堆栈执行。因此,两个调用相同函数的线程将具有各自的局部(堆栈)变量。因此,当您走进多线程领域时,了解堆栈概念是一件好事。
另一方面,在垃圾收集语言中,所有数据都被视为“在堆上”,并通过引用的计数(称为“指针”)进行访问。因此,例如在C#和Java中,您通常不会谈论“ stack-”变量与“ heap-”变量。
许多C ++类在内部实现一些“魔术”来为您优化其内部存储。例如,C ++字符串可以实现短字符串优化,因为它可以在本地(在堆栈上)存储“短字符串”,而在堆上(使用new
)存储长字符串。然后,它应用RAII惯用法来清除销毁时的所有堆内存。这样,作为客户的您通常不必在意。就像在您的示例中一样,您不必关心TArray如何处理其内部内存。您只需确保将值正确传递给它即可。
再次学习C ++,祝您好运:)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句