【问题标题】:Creating array of objects on the stack and heap在堆栈和堆上创建对象数组
【发布时间】:2010-12-08 13:50:33
【问题描述】:

考虑以下代码:

class myarray
{
    int i;

    public:
            myarray(int a) : i(a){ }

}

如何在栈上创建myarray的对象数组,如何在堆上创建对象数组?

【问题讨论】:

  • 这是一道作业题吗?听起来像一个。
  • 不...这不是家庭作业问题...在准备我的求职面试时在互联网上找到了这个...:)

标签: c++ arrays object heap-memory stack-memory


【解决方案1】:

您可以通过以下方式在堆栈上创建对象数组

myarray stackArray[100]; // 100 objects

在堆上(或“freestore”):

myarray* heapArray = new myarray[100];
delete [] heapArray; // when you're done

但最好不要自己管理内存。相反,请使用std::vector:

#include <vector>
std::vector<myarray> bestArray(100);

向量是一个动态数组,它(默认情况下)从堆中分配元素。††


因为你的类没有默认构造函数,要在堆栈上创建它,你需要让编译器知道将什么传递给构造函数:

myarray stackArray[3] = { 1, 2, 3 };

或者用一个向量:

// C++11:
std::vector<myarray> bestArray{ 1, 2, 3 };

// C++03:
std::vector<myarray> bestArray;
bestArray.push_back(myarray(1));
bestArray.push_back(myarray(2));
bestArray.push_back(myarray(3));

当然,你总是可以给它一个默认的构造函数:

class myarray
{
    int i;    
public:
    myarray(int a = 0) :
    i(a)
    {}
};

† 对于学究:C++ 并没有真正的“堆栈”或“堆”/“freestore”。我们拥有的是“自动存储”和“动态存储”持续时间。实际上,这与堆栈分配和堆分配保持一致。

††如果你想从堆栈中“动态”分配,你需要定义一个最大大小(堆栈存储提前知道),然后给向量一个新的分配器,以便它使用堆栈。

【讨论】:

  • 您可以使用_alloca()在堆栈上动态分配可变数量的内存...
  • @GMan - 这是一个非标准但广泛提供的 C 函数。
  • 它在 C++ 中的工作方式与在 C 中的工作方式相同;如果有更标准的方法告诉编译器在运行时确定 N 的堆栈上分配 N 个字节,我不知道它是什么。
  • 可能只是一个很小的细节,我不确定vector 是否指定元素将在堆上。例如,经典的string 实现通常将对象内部的字符保持在最多 8 或 16 个字符。然后当它需要拉长时,它会切换到堆。因此,如果 string 对象本身在堆栈上,则数据也在堆栈上,对于所有小于 16 的字符串。可以想象 vector 在实现中的行为相同,不是吗?
  • 对象数组不应该是双指针吗?因为每个对象保存在堆上时都是一个指针
【解决方案2】:

如果您创建一个 myarray 类的对象数组(在堆栈上或在堆上),则必须定义一个默认构造函数。

在创建对象数组时,无法将参数传递给构造函数。

【讨论】:

    【解决方案3】:

    我知道如何使用默认构造函数创建对象,但仅限于堆栈:

    假设你想用a = 1..10为 MyArray 类创建 10 个对象:

    MyArray objArray[] = { MyArray[1], MyArray[2]......MyArray[10]}
    

    不需要调用析构函数,因为它们是在堆栈中创建的。

    【讨论】:

    • 语法?使用圆括号,以下使用临时:MyArray objArray[] = { MyArray(0), MyArray(88), etc., }
    • 如前所述,这不会编译。
    【解决方案4】:
    #include <stdio.h>
    class A
    {
    public:
      A(int a){ 
           printf("\nConstructor Called : %d\n",a); 
           aM = a;
          }  
      ~A(){ 
        printf("\ndestructor Called : %d\n",aM);
    }
    private:
      int aM;
    };
    
    int main()
    {                                                                                                   
      A **a = new A*[10];
      for (int i = 0;i<10;i++)
        a[i] = new A(i+1);
        for (int i = 0;i<10;i++)
          delete a[i];// = new A(i+1);                                                                                    
    
      delete []a;
    }
    

    【讨论】:

    • 我也看不到 A 的任何数组在哪里,除非对象算作大小为 1 的数组。
    【解决方案5】:

    自 C++11 起,std::array&lt;T,size&gt; 可用于在堆栈上分配的数组。它包装了T[size],提供了std::vector的接口,但大多数方法是constexpr。这里的缺点是您永远不知道何时溢出堆栈。

    std::array<myarray, 3> stack_array; // Size must be declared explicitly.VLAs
    

    对于分配有堆内存的数组,使用std::vector&lt;T&gt;。除非您指定自定义分配器,否则标准实现将使用堆内存来分配数组成员。

    std::vector<myarray> heap_array (3); // Size is optional.
    

    注意在这两种情况下都需要一个默认的构造函数来初始化数组,所以你必须定义

    myarray::myarray() { ... }
    

    也有使用 C 的 VLAs 或 C++ 的 new 的选项,但应尽量避免使用它们,因为它们的使用会使代码容易出现分段错误和内存泄漏。

    【讨论】:

    • std::array 很好,因为 - 就像任何其他围绕 T[n 的编程良好的包装器一样 - 它知道自己的大小(通过模板魔法),可以以更令人愉悦的方式传递,可以从函数等返回。我确实喜欢“你永远不知道什么时候溢出堆栈” - 好吧,除非它导致非堆栈内存完全随机损坏并使其非常明显:-) 但当然,这是最好的以避免在堆栈上分配巨大的数组。
    猜你喜欢
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2017-11-08
    • 2021-08-09
    • 2016-12-15
    • 2012-08-12
    相关资源
    最近更新 更多