I wanted to initialize a vector of vectors that contain pointers to Courses. I declared this:
std::vector<std::vector<Course*> > *CSPlan =
new std::vector<std::vector<Course*> >(smsNum);
What I wanted to do by this is to have a vector of vectors, each inside vector is a vector that contains pointers to Courses, and I wanted the MAIN vector to be of size int smsNum. Furthermore, I wanted it on the heap.
My questions are:
Are both the main vector AND the inside vectors allocated on the heap? or is it only the MAIN vector is on the heap and its' indexes are pointers to other smaller vectors on the stack?
I declared it to be of size int smsNum so the Main vector is of size 10, but what about the smaller vectors? are they also of that size or are they still dynamic?
My goal in the end is to have a vector of vectors, both the Main vector and the child vectors on the heap, and ONLY the Main vector is of size smsNum, while the rest are dynamic.
Any structure that can grow as large as the user wants it to is going to be allocated on the heap. The memory stack, on the other hand, is used to allocate statically allocated variables, that the program has control of the size statically, during the compilation process.
Since you can have a loop like this:
for (i = 0; i < your_value; i++) {
vector.insert(...);
}
And considering your_value as an integer read from the standard input, the compiler have no control on how large will be your vector, i.e., it does not know what is the maximum amount of inserts you may perform.
To solve this, the structure must be allocated on the heap, where it may grow as large as the OS allows it to -- considering primary memory, and swap. As a complement, if you use the pointer to the vector, you'll be simply dynamically allocating a variable to reference the vector. This changes NOT the fact that the contents of the vector is, necessarily, being allocated on the heap.
You'll have, in your stack:
a variable "x" that stores the address of a variable "y";
And in your heap:
the value of the variable "y", that is a reference to your vector of vectors;
the contents of your vector of vectors (accessed by "y", that is accessed by "x").
Related
If I pass a vector by reference and and I push new elements to the vector and it has to dynamically resize the array while I push elements in the function, will the vector now be at a different location? How does the program ensure that it points to the new dynamically allocated location? Is it using a pointer to the pointer that points to the current array memory location which can be modified after resizing to point to a new contiguous memory location under the hood?
void func(vector<int> &vect)
{
vect.push_back(30);
}
int main()
{
vector<int> vect;
func(vect);
}
The answer is yes. You can confirm this to yourself by trying to figure out what's happening in your code sample. The key insight is that anything allocated non-dynamically must have a fixed size at allocation time.
You don't have a pointer here, so the core data structure of the vector is getting allocated on the stack, where it can't just grow into other things that are potentially on top of it in the stack. For instance, while you're inside func(), the function call to func is on the stack on top your vector variable. It's impossible for it grow there without overwriting the stack frame for your function call. If it did that, your program would crash when trying to return from func.
So, the only way it could possibly grow is if, internally, it dynamically allocated memory in a different location as needed. So, this must be what's happening under the hood.
Suppose I want to represent a two-dimensional matrix of int as a vector of vectors:
std::vector<std::vector<int> > myVec;
The inner dimension is constant, say 5, and the outer dimension is less than or equal to N. To minimize reallocations I would like to reserve space:
myVec.reserve(N);
What size is assumed for the inner vector? Is this purely implementation dependent? How does this effect the spatial locality of the data? Since the inner dimension is a constant is there a way to tell the compiler to use this constant size? How do these answers change if the inner vector's size changes?
Since your inner dimension is constant, I think you want
std::vector< std::array<int, 5> > vecs;
vecs.reserve(N);
This will give you preallocated contiguous storage, which is optimal for performance.
The size of the inner vectors is completely irrelevant for resizing the outer vector. There are no locality guarantees for your bundle of vectors, the locality guarantee (i.e. contiguous block in memory) exists for a single vector only.
Remember that a vector object itself has constant sizeof-size, its actual data is usually dynamically allocated. The outer vector, to first approximation, is a contiguous block of N 'pointers' to the inner vectors. Your reserve call does not reserve memory for possible elements of inner vectors, but only for the inner vector objects themselves (i.e. their bookkeeping data and their pointers to their dynamically allocated data block).
The inner vectors are initialized with the default constructor. So if you write:
vector<vector<int> > vecs;
vecs.reserve(10);
This is equivalent to calling the constuctor of vector<int> or vector<int>() for each element. Which means you'll have a zero-sized vectors. But remember, you can't use them unless you resize (not reserve) your vectors.
Remember, too, that it could be sometimes more efficient to resize with the initial size that you would need. So it's useful to do something like
vector<vector<int> > vecs(3,vector<int>(5));
This will create a vector with size 3, and each element will contain a vector of size 5.
Remember also, that it could be more efficient to use deque rather than vector if you're going to resize your vectors often. They're easy to use (as vectors) and you don't need to reserve, since the elements are not contiguous in memory.
In C++, the delete[] operator deletes an array. It is able to access the length of the array because the allocator keeps track of it.
Does that mean that a flattened one-dimensional array takes up less memory than a multi-dimensional array?
To be more specific, if I allocate Object** c, does the allocator store the lengths of both the first and second dimensions, while allocating Object* c (but with the same number of elements as the two-dimensional array) only stores one length?
If you do this:
Object **c = new Object*[n];
for (size_t i=0; i!=n; ++i) {
c[i] = new Object[m];
}
then it will typically take more memory than doing this:
Object *c = new Object[n*m];
for just the reasons you stated.
Every memory allocation has a certain amount of overhead. In addition to needing to keep the number of elements, there is overhead for the memory allocator itself. It also takes more memory for all the extra pointers for each row.
Note that it is possible to have a situation where breaking it up would use less memory. If your heap was fragmented, then finding one large chunk of memory may require allocating more memory from the operating system, whereas if your array was broken into smaller pieces, those pieces may be able to fit in the holes of your fragmented heap.
How to allocate memory to Vector dynamically ?
vector<Point> vInPts; // My Input Vector - i have dumped some value ( of size 6 )
// Doing Some calculation on the input vector points
vector<Point> vOutPts; // How to dynamically allocate memory for this output vector Points
Chances are you do not need to allocate the vector itself dynamically. Internally, the vector will allocate the memory it needs to store its elements dynamically, and will take care of managing this memory. So just declare the vector in automatic storage:
vector<Point> vOutPts;
You can allocate a predetermined amount of memory for the vector by calling std::vector::reserve.
If you absolutely must allocate the vector dynamically, make sure you know all about memory management, and read up on smart pointers and RAII.
If you know the size you want, then you can allocate and initialise enough elements with:
vOutPts.resize(size);
or you can create it with that size:
vector<Point> vOutPts(size);
Otherwise, you can grow the vector one element at a time:
vOutPts.push_back(some_point);
If you know (roughly) how many elements you want to push, then you could make that a bit more efficient by allocating some memory beforehand, without initialising any elements:
vOutPts.reserve(approx_size);
This way
vector <Point> *myvect= new vector<Point>()
But don't forget to call:
delete myvect
when you're done using it or else you'll create a leak.
Please notice that allocating the vector itself this way won't be the same as allocating dinamically the vector contents. This dynamic allocation of the vector itself should be done only if for example you intend to create a vector inside a function and return it by reference. Automatic memory management is easier to handle, less error prone and above all safer than dynamically allocating objects... and therefore whenever you don't have to you should avoid this dynamic allocation
How is std::vector implemented, using what data structure? When I write
void f(int n) {
std::vector<int> v(n);
...
}
Is the vector v allocated on stack?
The vector object will be allocated on the stack and will internally contain a pointer to beginning of the elements on the heap.
Elements on the heap give the vector class an ability to grow and shrink on demand.
While having the vector on the stack gives the object the benefit of being destructed when going out of scope.
In regards to your [] question, the vector class overloads the [] operator. I would say internally it's basically doing something like this when you do array[1]:
return *(_Myfirst+ (n * elementSize))
Where the vector keeps track of the start of it's internal heap with _Myfirst.
When your vector starts to fill up, it will allocate more memory for you. A common practice is to double the amount of memory needed each time.
Note that vector inherits from _Vector_val, which contains the following members:
pointer _Myfirst; // pointer to beginning of array
pointer _Mylast; // pointer to current end of sequence
pointer _Myend; // pointer to end of array
_Alty _Alval; // allocator object for values
Your v is allocated in automatic memory. (commonly known as the stack, yes)
The implementation details are not specified, but most commonly it's implemented using a dynamic array which is resized if you attempt to add more elements than the previous allocation can hold.
The standard only specifies the interface (which methods it should have) and execution time boundaries.
Since vector is a template, the implementation is visible, so locate your <vector> file and start inspecting.
void f(int n) {
std::vector<int> v(n);
...
}
The vector above has automatic storage duration and is allocated on the stack. However, the data array that the vector manages is allocated on the heap.
The internals of the vector are implementation specific, but a typical implementation will contain 3 pointers; one each to keep track of start of array, size of vector and capacity of vector.