C++ stack-based object allocation - c++

In C++ there are two ways one can declare an object. For example:
// The first way
vector<int> *nums = new vector<int>;
// The second way
vector<int> nums;
People say that the first declaration allocates the object in the heap and the second on the stack. I can imagine how it works if the vector object is in the heap. The compiler would just find a free block in the heap to store the vector. But what would happen if the object is allocated on the stack as I keep pushing new elements to the vector? Will there be enough memory space? If not, how would the compiler find a sufficiently big memory block on the stack to store the vector when the size of the vector can change?

Putting vector object on stack doesn't mean it will put its elements on stack. Check documentation:
Internally, vectors use a dynamically allocated array to store their elements. This array may need to be reallocated in order to grow in size when new elements are inserted, which implies allocating a new array and moving all elements to it.
From: http://www.cplusplus.com/reference/vector/vector/

Related

how c++ vector<vector<int>> manages memory

vector container holds object in continuous memory. it is easy to understand for cases like vector. but what if it is a vector of vectors, like vector>, each vector in this vector of vectors can have different length. how does it manage the memory? Does it allocate a fixed length vector every time we push in a new vector? if so, what will happen if the first vector grows out of size during push_back. would it trigger a full vector of vector reallocate and copy/move?
A vector is a pointer to a dynamic array. If you push_back and find you're out of space in the array you have, you allocate a new, bigger array, copy over everything from the old array, and then stick the new value in.
If you have a vector of vectors, the same holds true for each of the inner vectors.
What you need to understand here is that a vector of vectors (unlike a 2D array), is not contiguous in memory. Each of the inner vectors' arrays can be stored anywhere in memory. Or in other words, "each vector in a vector of vectors is a completely different vector. Each with their own, completely separate and separately managed buffer.1"
1. Thanks to user4581301 for this!
A vector contains a pointer to a contiguous memory block. When it runs out of memory, it allocates a new memory block. A vector of vectors is just a vector of pointers to memory blocks. Although each memory block is a contiguous block, they are not necessarily contiguous to each other, that is, not necessarily when one vector ends, the next one starts, there is almost always a gap.
Why the not necessarily and almost always semantics? Because it depends on the memory allocator you're using and on the operating system internals. Ultimately, it's (one of) the job(s) of the OS to allocate and serve memory blocks to user-space programs.

How to reuse a memory block previously allocated to a vector in c++

I have multiple vectors of structure objects for different structures. Now I want to reuse the same memory for all the vector objects.i.e,Once my work is done with one vector i want to erase its elements from the memory and assign that memory to the other vector.
i.e.The first vector is of one structure type object and the second vector is a structure type object of a completely different structure.
I am using windows 8.1 64-bit.
When you erase vector elements, the memory allocated for the vector elements is not freed until you call std::vector::shrink_to_fit. Thus you do not have to do special actions to reuse the allocated memory.
It is not clean what you mean under
Once my work is done with one vector i want to erase its elements from
the memory and assign that memory to the other vector.
You could continue using the same vector with the same memory, or you can call v1.swap(v2) to exchange allocated memories of two vectors, or you can move allocated memory of one vector to another v2 = std::move(v1).
It is applicable to vectors containing elements of a same type or pointers, that is not suitable to your case.
Being able to move allocated memory from a vector of one type to a vector containing another is not a feature supported by std::vector. I would suggest writing/finding another container that fits your needs.

Is an array of vectors entirely contiguous memory?

I know vectors are guaranteed to be contiguous memory, and so are arrays. So what happens when I do something like this:
std::vector<uint8_t> my_array[10];
my_array[2].push_back(11);
my_array[2].push_back(7);
What would the memory look like? If both need to be contiguous, would every element of the array after my_array[2] be pushed forward a byte every time I do a push_back() on my_array[2]?
Would this be the same situation as when I have an array of structs, where the structs have a member that has a variable size, such as a string or another vector?
Memory footprint of std::vector consists of two parts:
The memory for the std::vector object itself (very small, and independent of the size), and
The memory for the data of the vector (depends on the number of elements in the vector).
The first kind of data will be contiguous in an array; the second kind of data is allocated dynamically, so it would not be contiguous in an array.
This would not be the same as with a C struct that has a flexible data member, because the data portion of std::vector is not always allocated in the same kind of memory, let alone being adjacent to it. The vector itself may be allocated in static, dynamic, or automatic memory areas, while its data is always in the dynamic area. Moreover, when vector is resized, the memory for its data may be moved to a different region.
Each time you call push_back, std::vector checks if it has enough dynamic memory to accommodate the next data element. If there is not enough memory, then the vector allocates a bigger chunk of memory, and moves its current content there before pushing the new item.
The vector memory structure is contiguous in memory; however std::vector's all contain a pointer pointing to dynamically allocated memory for the actual storage (which is very very likely not contiguous).
Knowing this, std::vector::push_back will only check to see if the (external) dynamically allocated array has enough capacity to hold the new item, if not it will reallocate space. A push_back on the first vector that overflows will not cause the second vector in the array to reallocate memory, that isn't how it works.
Also, there is no such thing as a struct having a variable size, the size of structures and classes have to be known at compile time.
std::string also has a fixed size, although you may think it is variable, because it also (like vector) has a pointer to the char* it contains.

c++ memory issue about pointer + non pointer

Let's say I have declared a variable
vector<int>* interList = new vector<int>();
interList->push_back(1);
interList->push_back(2);
interList->push_back(3);
interList->push_back(4);
First question is when I push_back an int, a memory space will be consumed?
Second question if I (delete interList), will the memory consume by 1,2,3,4 be released automatically?
EDIT: free --> delete
Yes, the vector class will probably automatically allocate a larger space than needed in case you want to store more data in it later, so it probably won't allocate new space each time you push_back().
Yes, but you should use delete interList; instead of free().
std::vector allocates continuos block of memory at once for some amount of elements. So every time you insert new element it is inserted into reserved block, and the memory space remains the same, no new allocation happens.
If you insert element beyond the allocated block (capacity of the vector) then it allocates a bigger block (resize), copies all the previous elements into it and destroys the old block. So vector manages memory by itself, not each inserted element cause reallocation of the internal buffer.
Second question - yes, vector will clean up all the memory if you delete vector itself.
delete interList;
push_back copies the elements to the heap where the vector will allocate array to store the elements. The capacity of vector can be greater than required or greater than how many elements the vector has. Every time a push back happens the vector checks if there is enough space and if there isn't then it moves all the elements to bigger space and then push elements to the array. The vector always puts elements to contiguous memory blocks and hence if the memory block is not large enough to hold all elements together then it moves all the elements to larger block and appends new elements. In order to avoid this frequent moving the vector would usually allocated bigger memory block.
delete interList would destroy the vector and the integers hold by the vector. Here the vector would be on heap as well as the integers also would be on heap. Actually it is better to create the vector on stack or as a member of other object like vector<int> interList; The vector though on stack stores the elements of int on heap as a array. And as ints are stored as value types then once the vector goes out of scope then the memory of ints would be reclaimed.
Because the vector has value types. They are copied to heap by the vector and stored and managed as arrays and their lifetime is attached with vector's lifetime. If you have a vector of pointers then you have to worry. Like vector<T*> list; list.push_back(new T()); The list stores pointers to objects of type T. When you destroy such vector the T objects would not be deleted. This is same like a class with a pointer to a T*. You have to loop through all the element and call delete on pointers or use vector of shared pointers. Vector of shared pointers or unique pointers is recommended.
You are better off not directly allocating the vector if you can help it. So your code would look like this:
vector<int> interList;
interList.push_back(1);
interList.push_back(2);
interList.push_back(3);
interList.push_back(4);
Now when interList goes out of scope all memory is freed. In fact this is basis of all resource management of C++, somewhat prosaically called RAII (resource acquisition is initialization).
Now if you felt that you absolutely had to allocate your vector you should use one of the resource management smart pointers. In this case I'm using shared_ptr
auto interList = std::make_shared<vector<int>>();
interList->push_back(1);
interList->push_back(2);
interList->push_back(3);
interList->push_back(4);
This will now also free all memory and you never need to call delete. What's more you can pass you interList around and it will reference count it for you. When the last reference is lost the vector will be freed.

STL containers on the stack and the heap

If std::vector and friends are self resizing, does that mean if I declare a vector like so:
std::vector<string> myvec;
Then it'll resize using more stack, whereas:
std::vector<string> *myvec = new std::vector<string>();
Would resize using more heap?
Vectors allocate on the heap in their internals.
The only thing you pay for in the stack for a stack based bector is a couple of bytes, the inner buffer will always be allocated from the heap.
So effectively when you do a vec = new vector() you are allocating a small quantity, which may not be really good.
In the first case, you are creating the vector on stack. That doesn't mean that all the vectors internal objects are on stack as well. In fact, vector will still allocate the memory required to hold the objects on heap only. This is because, to allocate on stack you should know how many objects to create. But this information is not available, so the only remaining option is to allocate the memory for the contained object from heap.
std::vector always has its buffer allocated on heap. So regardless of where the vector itself is allocated resizing it will only affect the heap.