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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/320506/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:36:43  来源:igfitidea点击:

C++: how to create an array of objects on the stack?

c++arraysstackoop

提问by Leonel

Consider the following piece of Java code.

考虑下面的一段 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);
}

Because in Java, all objects live on the Heap, the array does not contain the objects themselves, but references to the objects. Also, the array itself is also an object, thus it lives on the heap.

因为在 Java 中,所有对象都存在于 Heap 中,数组不包含对象本身,而是包含对对象的引用。此外,数组本身也是一个对象,因此它存在于堆中。

What is the equivalent in C++, but keeping the array and objects on the stack, to avoid as much as possible needing new and delete ?

C++ 中的等价物是什么,但将数组和对象保留在堆栈上,以尽可能避免需要 new 和 delete ?

Edit: changed the code to use a custom constructor.

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

采纳答案by Steve Jessop

For an array of ArrayList objects:

对于 ArrayList 对象数组:

ArrayList obj[10];

The objects will be default initialised, which is fine for user-defined types, but may not be what you want for builtin-types.

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

Consider also:

还要考虑:

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

This initialises the objects by copying whatever you pass as the second parameter. So they're all the same, but not necessarily default. And as litb points out, the "10" in the vector can be replaced by a non-constant expression, whereas the "10" in the array declaration can't.

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

This doesn't actually put the ArrayList objects on the stack, it puts all 10 in a single allocation from the heap. So there may very rarely be performance concerns, if you really can't afford a single allocation. However, the std::vector is on the stack and it deletes any heap objects it uses when it is destroyed. So for the purposes of making sure your resources are freed, the vector behaves "as though" it were all on the stack.

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

Note that mixing a container of Object, with ArrayList values, as you do in your example Java code, is fraught with peril in C++. Basically you can't do it, even if ArrayList extends Object, because the array would only contain the storage for 10 Objects, and ArrayList likely requires more bytes to store than Object. The result is that any ArrayList you try to copy into the array would get "sliced": only the initial part of its representation is put in the array.

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

If you want a container of a type saying that it contains Objects, but which actually contains ArrayLists, then you need a container of pointers. To get good resource-handling, this probably means you need a container of smart pointers.

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

回答by Joris Timmermans

Simply declaring

简单地声明

Object array_of_objects[10];

in C++ creates 10 default-constructed objects of type Object on the stack.

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

If you want to use a non-default constructor, that's not so easy in C++. There might be a way with placement new but I couldn't tell you off the top of my head.

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

EDIT: Link to other question on StackOverflowHow to use placement new for the array is explained in the answer to this questionhere on StackOverflow.

编辑:链接到 StackOverflow 上的其他问题How to use placenew for the array在 StackOverflow 上这个问题的答案中进行了解释。

回答by Johannes Schaub - litb

In C++, it is not possible to have an array on the stack with a size determined at runtime. Here you use std::vector to do that:

在 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

If the size is known at compile-time, you can just go ahead with a plain array:

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

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

If you are allowed to use boost, it is better to use boost::array , since it provides iterators like containers do, and you will be able to get its size using .size():

如果你被允许使用 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

回答by xtofl

Allocation can be done 'statically' (size known at compile time) or 'dynamically' (size determined at run time).

分配可以“静态”(编译时已知大小)或“动态”(运行时确定大小)完成。

Static allocation is the plain old

静态分配是老生常谈

int myarray[10];

To allocate on the stack, you need the allocaallocation function, which essentially just increments the stack pointer. (or decrements... whatever). Deallocation is done automatically.

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

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

So you can initialize an array on the stack like Nilsshowed.

所以你可以像Nils展示的那样在堆栈上初始化一个数组。

std::vectorcanwork on the stack if provided a stack-allocator (the second, cumbersome template argument of vector)

std::vector如果提供堆栈分配器( 的第二个繁琐的模板参数vector),则可以在堆栈上工作

My guess is that Boost does just this.

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

回答by Nils Pipenbrinck

You can even allocate variable numbers of objects on the stack. You have to mix C and C++ to do so though.

您甚至可以在堆栈上分配可变数量的对象。你必须混合 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])();

Code is untested, but in principle it works that way.

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

回答by Elliott

If you happen to use Qt, you can use the QVarLengthArray

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

It takes a size as a second template parameter, and it will statically allocate an array with that size, and use that as the backing for the array instead of the heap like a std::vector or QVector does. If you add more than the template-specified size, it'll use heap allocation instead.

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

Example:

例子:

//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

If you stay below the template parameter size, you'll avoid the performance hit of a heap allocation - you'll effectively have a dynamically allocated stack-based array. The only disadvantage is that it's wasteful of memory if you don't use exactly as many items as the template parameter specifies: If you use too few, then the empty spaces are wasted. if you use too many, then the entire stack allocated area is wasted.

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

Sometimes trading performance for memory is worth it, and sometimes it isn't. I would recommend against blindly using this class - only use it if you knowvia profiling that the heap allocation of std::vector is one of your program's bottlenecks.

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