也许我还不了解C ++中的堆和堆栈的概念

马蒂亚斯

我正在(重新)学习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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章