考虑以下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?
编辑:更改代码以使用自定义构造函数。
答案 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的堆分配是你程序的瓶颈之一。