C ++:如何在堆栈上创建对象数组?

时间:2008-11-26 12:17:38

标签: c++ arrays stack oop

考虑以下Java代码。

int N = 10;
Object obj[] = new Object[N];
for (int i = 0; i < N; i++) {
    int capacity = 1000 * i;
    obj[i] = new ArrayList(capacity);
}

因为在Java中,所有对象都存在于堆中,所以数组不会 包含对象本身,但引用对象。也, 数组本身也是一个对象,因此它存在于堆上。

C ++中的等价物是什么,但保持数组和对象 堆栈,尽量避免需要new和delete?

编辑:更改代码以使用自定义构造函数。

6 个答案:

答案 0 :(得分:5)

简单地声明

Object array_of_objects[10];
C ++中的

在堆栈上创建了10个类型为Object的默认构造对象。

如果你想使用非默认的构造函数,那么在C ++中就不那么容易了。可能有一种新的放置方式,但我不能告诉你我的头脑。

编辑:链接到StackOverflow上的其他问题 在StackOverflow的this question答案中解释了如何使用数组的新位置。

答案 1 :(得分:4)

在C ++中,不可能在堆栈上有一个数组,其大小在运行时确定。在这里你使用std :: vector来做到这一点:

int N = 10;
std::vector<Object> obj(N);
// non-default ctor: std::vector<Object> obj(N, Object(a1, a2));
// now they are all initialized and ready to be used

如果在编译时已知大小,则可以继续使用普通数组:

int const N = 10;
Object obj[N];
// non-default ctor: Object obj[N] = 
//     { Object(a1, a2), Object(a2, a3), ... (up to N times) };
// now they are all initialized and ready to be used

如果允许使用boost,最好使用boost :: array,因为它提供了像容器这样的迭代器,你可以使用.size()来获取它的大小:

int const N = 10;
boost::array<Object, N> obj;
// non-default ctor: boost::array<Object, N> obj = 
//     { { Object(a1, a2), Object(a2, a3), ... (up to N times) } };
// now they are all initialized and ready to be used

答案 2 :(得分:3)

对于ArrayList对象的数组:

ArrayList obj[10];

对象将默认初始化,这对于用户定义的类型很好,但可能不是你想要的内置类型。

还要考虑:

std::vector<ArrayList> obj(10, ArrayList());

通过复制传递的任何内容作为第二个参数来初始化对象。所以它们都是一样的,但不一定是默认的。正如litb指出的那样,向量中的“10”可以用非常量表达式替换,而数组声明中的“10”则不能。

这实际上并没有将ArrayList对象放在堆栈上,它将所有10个放在堆中的单个分配中。因此,如果您真的无法负担单一分配,那么可能很少会出现性能问题。但是,std :: vector在堆栈上并删除它在销毁时使用的任何堆对象。因此,为了确保释放资源,向量的行为“好像”它们都在堆栈中。

请注意,将Object的容器与ArrayList值混合,就像在示例Java代码中一样,在C ++中充满了危险。基本上你不能这样做,即使ArrayList扩展了Object,因为该数组只包含10个对象的存储,而ArrayList可能需要比Object更多的字节存储。结果是,您尝试复制到数组中的任何ArrayList都将被“切片”:只将其表示的初始部分放入数组中。

如果你想要一个类型的容器,说它包含Objects,但实际上包含ArrayLists,那么你需要一个指针容器。为了获得良好的资源处理,这可能意味着您需要一个智能指针容器。

答案 3 :(得分:3)

分配可以'静态'(在编译时已知大小)或'动态'(在运行时确定大小)。

静态分配是普通的

int myarray[10];

要在堆栈上分配,您需要alloca分配函数,它实际上只是递增堆栈指针。 (或减少...无论如何)。解除分配是自动完成的。

int* myarray = (int*) alloca( n*sizeof(int) );

所以你可以在堆栈上初始化一个数组,如Nils所示。

如果提供了一个stack-allocator(std::vector的第二个,繁琐的模板参数)

vector 可以在堆栈上工作

我的猜测是Boost就是这样做的。

答案 4 :(得分:2)

您甚至可以在堆栈上分配可变数量的对象。你必须混合C和C ++才能这样做。

// allocate storage for N objects on the stack
// you may have to call _alloca and include something to use this.
object * data = (object *) alloca (N * sizeof (object));

// initialize via placement new.
for (int i=0; i<N; i++)
  new (&data[i])();

代码未经测试,但原则上它是这样工作的。

答案 5 :(得分:0)

如果您碰巧使用Qt,可以使用QVarLengthArray

它需要一个大小作为第二个模板参数,它将静态地分配具有该大小的数组,并将其用作数组的后备而不是像std :: vector或QVector那样的堆。如果添加超过模板指定的大小,则会使用堆分配。

示例:

//the following ints will all be stored on the stack,
//and a heap allocation is never performed to store the array
QVarLengthArray<int, 10> objArray;
for (int i = 0; i < 8; i++) {
    int capacity = 1000 * i;
    objArray.push_back(capacity);
}

//since it's a class and not a raw array, we can get the array's size
std::cout << objArray.size(); //result is 8

//a heap allocation will be performed if we add an eleventh item,
//since the template parameter of 10 says to only statically allocate 10 items
objArray.push_back(0); //9 items
objArray.push_back(0); //10 items
objArray.push_back(0); //11 items - heap allocation is performed

如果你保持低于模板参数大小,你将避免堆分配的性能损失 - 你将有效地拥有一个动态分配的基于堆栈的数组。唯一的缺点是,如果不使用与模板参数指定的项目完全相同的项目,则会浪费内存:如果使用的项目太少,则会浪费空白空间。如果使用太多,那么整个堆栈分配区域就会浪费掉。

有时,内存的交易性能是值得的,有时则不然。我建议不要盲目地使用这个类 - 只有在知道时才使用它,通过分析std :: vector的堆分配是你程序的瓶颈之一。