Consider the following piece of Java code.
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.
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 ?
Edit: changed the code to use a custom constructor.
Simply declaring
Object array_of_objects[10];
in C++ creates 10 default-constructed objects of type Object on the stack.
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.
EDIT: Link to other question on StackOverflow How to use placement new for the array is explained in the answer to this question here on StackOverflow.
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:
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():
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
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 alloca
allocation function, which essentially just increments the stack pointer. (or decrements... whatever). Deallocation is done automatically.
int* myarray = (int*) alloca( n*sizeof(int) );
So you can initialize an array on the stack like Nils showed.
std::vector
can work on the stack if provided a stack-allocator (the second, cumbersome template argument of vector
)
My guess is that Boost does just this.
For an array of ArrayList objects:
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With