Pointer to Vector Memory Loss - c++

I have come against a problem with my pointer vectors...
And i got an idea what the problem might be:
When I create a pointer to a vector, the pointer reserves the size of the vector on the heap. So that basicly means, that the pointer now points to the memory of the vector without anything inside... When i now resize or pushback the vector, will the pointer now still point to the whole memory of the vector or just the memory which has been allocated at the beginning?
I also want to know, if there are some tricks you can do to fix that (if what i think is true). Is the "vector.reserve(n)" a method of accomplishing this? Or is there something i could do to overwrite the pointers memory adress, to a vector after it has been initialised?

"When I create a pointer to a vector, the pointer reserves the size of the vector on the heap.
No, it doesn't! When you create a pointer to a vector, you have a pointer. Nothing more. It doesn't point to anything yet, and it certainly hasn't reserved any "heap memory" for you.
You still need to actually create the vector that will be pointed-to.
std::vector<int>* ptr1; // just a pointer;
ptr1 = new std::vector<int>(); // there we go;
delete ptr1; // don't forget this;
auto ptr2 = std::make_shared<std::vector<int>>(); // alternatively...
Y'know, it's very rare that you need to dynamically-allocate a container. Usually you just want to construct it in the usual fashion:
std::vector<int> v;
That's it. No need for pointers.
When i now resize or pushback the vector, will the pointer now still point to the whole memory of the vector or just the memory which has been allocated at the beginning?
Regardless of how you constructed/allocated it, the vector itself never moves spontaneously (only the dynamic memory that it is managing for you internally), so you do not need to worry about this.
I also want to know, if there are some tricks you can do to fix that
No need, as there's nothing to fix.
Is the "vector.reserve(n)" a method of accomplishing this?
Theoretically, if this were a problem (which it isn't) then, yes, this could possibly form the basis of a solution.

Vector is class that has internal pointer to vector's elements using continuous block of memory in the heap. Long enough for all reserved vector's elements (capacity() method)
So, if you create vector (in local scope's stack OR in the heap - doesn't matter) it creates this layout
[ vector [ ptr-to-data ] ] --> HEAP: [ 1 ][ 2 ][ 3 ]
vector<int> v1(3); // whole vector instance in the stack
vector<int> *pv2 = new vector<int>(3); // pointer to vector in the heap
each of these 2 vector instances has its pointer to its elements in the heap as well
Vector manages its pointer to the data internally.
When you push_back() more elements than its current .capacty() it will re-allocate new continuous block of memory and copy-construct or move all old elements to this new block.

Related

Stack vs Heap - Should objects inside *vector be declared as pointers?

If I use this line
std:vector<MyObject>* vec = new std::vector<MyObject>(100);
If I create MyObject's in the stack and add them to the vector, they remain in the stack, right ?
MyObject obj1;
vec->push_back(obj1);
So if it go to the stack, than MyObject's added to the vector will be gone after method ends ? What will I have inside the vector than? Garbage?
Should I use this instead ?:
std:vector<MyObject*>* vec = new std::vector<MyObject*>(100);
And if so, what about objects and primitives inside each MyObject ?
Should they also be dynamically created ?
Thank You
The std:vector as any other Standard Library container copies elements into itself, so it owns them. Thus, if you have a dynamically allocated std::vector the elements that you .push_back() will be copied into the memory managed by the std::vector, thus they will be copied onto the heap.
As a side note, in some cases std::vector may move elements if it is safe to do so, but the effect is the same - in the end, all the elements are under std::vector's jurisdiction.
A std::vector<MyObject> looks something like this (in reality it's much more complex):
struct Vector {
MyObject* data;
int size;
}
As you can see, the data is not directly inside the vector object. The vector always allocates the memory for the data on the heap. Here's what happens when:
you call .push_back: The vector copies the object into its own data block (which is on the heap and owned by the vector)
you copy the vector: The copied vector allocates new memory and copies all data from the existing vector into it
As you can see, the vector owns his data. That means, if you push_back a object into it, it doesn't matter where it came from because it gets copied.
If you have a std::vector<MyObject>* you have a pointer to a vector. This vector also owns his data, but you only have a pointer to it. That means, you have to delete it exactly once, otherwise you'll get a memory leak or a crash. Passing around pointers to a vector is OK, but need one class or function that "owns" it. This class/function has to guarantee that the vector still exists when the pointer to it is used.
The third case is a std::vector<MyObject*>. As every vector, this one also owns his data. But this time, the data is only a pointer. So the vector only owns the pointer, but not the objects to which the pointers are pointing. If you do something like this:
std::vector<MyObject*> getObjects() {
MyObject obj1("foo");
MyObject obj2("bar");
std::vector<MyObject*> vec;
vec.push_back(&obj1);
vec.push_back(&obj2);
return vec;
}
The returned vector only contains garbage because you only saved the address to a object on the stack to it. These objects are destroyed when the function returns, but the pointers in the vector are still pointing to that memory block on the stack.
Additionally, keep in mind that this
std:vector<MyObject*>* vec = new std::vector<MyObject*>(100);
Doesn't store heap allocated objects to the vector. It just stores pointers of type MyObject. If you want to do something like that remember to create the objects first, before you use them. You can do that with something like the following:
for (int i = 0; i < vec->size(); i++) {
vec->at(i) = new MyObject();
}

Use a ::std::vector for array creation

I want to grow a ::std::vector at runtime, like that:
::std::vector<int> i;
i.push_back(100);
i.push_back(10);
At some point, the vector is finished, and i do not need the extra functionality ::std::vector provides any more, so I want to convert it to a C-Array:
int* v = i.data();
Because I will do that more than once, I want to deallocate all the heap memory ::std::vector reserved, but I want to keep the data, like that (pseudo-code):
free(/*everything from ::std::vector but the list*/);
Can anybody give me a few pointers on that?
Thanks in advance,
Jack
In all the implementations I have seen, the allocated part of a vector is... the array itself. If you know that it will no longer grow, you can try to shrink it, to release possibly unused memory:
i.shrink_to_fit();
int* v = i.data();
Of course, nothing guarantees that the implementation will do anything, but the only foolproof alternative would be to allocated a new array, move data from the vector to the array and clear the vector.
int *v = new int[i.size];
memcpy(v, i.data, i.size * sizeof(int));
i.clear();
But I really doubt that you will have a major gain that way...
You can use the contents of a std::vector as a C array without the need to copy or release anything. Just make sure that std::vector outlives the need for your pointer to be valid (and that further modifications which could trigger a reallocation are done on the vector itself).
When you obtain a pointer to internal storage through data() you're not actually allocating anything, just referring to the already allocated memory.
The only additional precaution you could use to save memory is to use shrink_to_fit() to release any excess memory used as spare capacity (though it's not guaranteed).
You have two options:
Keep data in vector, but call shrink_to_fit. All overhead you'll have - is an extra pointer (to the vector end). It is available since C++ 11
Copy data to an external array and destroy the vector object:
Here is the example:
std::vector<int> vec;
// fill vector
std::unique_ptr<int[]> arr(new int[vec.size()]);
std::copy(vec.begin(), vec.end(), arr.get());

C++ - For a vector of pointers to an object, does reallocation cause deletion and copying of objects?

From my understanding so far, if you have a vector of class objects, if you erase any member of the vector, typically the vector will reallocate some of it's objects in order to preserve memory contiguousness. Hence you need to implement the rule of three (destructor, copy constructor and copy assignment operator) for everything to be preserved when erasing vector members.
However: for a vector of pointers to class objects the outcome is less clear to me.
If I erase a member, then surely C++ is smart enough to just copy the pointers around - not maddeningly delete the pointer (and the class object it points to) then re-create it and the object it points to again?
If this is not the case, can someone explain this idiocy to me?
The vector will delete, construct, and copy whatever type it contains. In the case of a vector of pointers to a class/structure, it will delete, construct, and copy pointers, leaving the actual objects the pointers point to alone. It is up to you to allocate and deallocate these.
EDIT
An example:
If you have the following:
class A
{
A() {}
}
void foo(void)
{
A * pointerToA = new A;
}
At the end of the function foo's scope the only thing that is deallocated is the memory for the variable pointerToA itself, i.e. 4 bytes that hold an address (in 32 bit) - which in this case is stored on the stack. The only way that the memory allocated for a new instance of class A will be freed is if you manually call delete with the address to pointerToA.
Let's take the example of an array of class A
A ** arrayOfPointerToA = new A*[10];
for(unsigned i = 0; i < 10; ++i)
arrayOfPointerToA[i] = new A;
which is similar to what happens when you have std::vector<A*>. When you call
delete [] arrayOfPointerToA;
you're deallocating the memory for the array of pointers, not for each A.
In the above diagram, the memory deallocated by the above call to delete is highlighted in red. Note that each A is stored at a random location in memory in this instance since they were all allocated separately.
Now taking this to a vector:
A std::vector<A> effectively uses new A[size] to allocate memory. If you're storing a raw pointer, this would mean it would allocate an array of type A, which means that size number of objects of type A are created. When the vector frees its memory size number of objects of type A are destroyed. Now take that example and replace A with A* and you'll see that no objects of type A are destroyed.
This is a fundamental part of how C++ and pointers work, not just a property of containers. If containers did arbitrarily call delete on each member, this wouldn't make sense as when we have a container A we would call delete on an instance of an object instead of a pointer to that object which is not valid.
The vector will leave your pointer values alone. It of course will move the values in the internal array when you push, pop, or erase.
In this case the values are just pointers. But there is no logic in the vector to determine if something is a pointer to an object and delete/reallocate them when the values are copied.
In the case of a vector that includes a complex type and not a pointer it will of course try to copy the values when the internal array is reallocated or moved.

Moving an array held by a unique_ptr into a vector's array storage

Is there a way to move a unique_ptr
unique_ptr<int[]> foo;
into a vector?
vector<int> bar;
No, you cannot just hand vector a piece of memory and expect it to use that as its array storage. A vector's storage must come from the allocator that the vector uses.
You could try to use allocator gimmicks to pawn the memory off to the vector in some way. But even that would be tricky, as the vector can allocate as many ints as it wants, regardless of what size you tell it.
You can move the contents of a unique_ptr into an element of the array. Say, if you had a vector<unique_ptr<int[]>>. But you can't just slap a piece of memory into a vector.

Vector of ints on heap and freeing memory

I'm creating a vector of ints on the heap like this:
std::vector<int> vec = *new std::vector<int>();
then I get to the end of my program and I need to free the memory, but using vec.clear() doesn't free the memory.
How do I do this properly?
Thanks and all the best
-Mitchell
How do I do this properly?
Replace this:
std::vector<int> vec = *new std::vector<int>();
With this:
std::vector<int> vec;
Problem solved.
Unlike other languages you may have come across, new is best avoided in most situations. It dynamically allocates objects, like in other languages. But unlike other languages, C++ doesn't have a garbage collector, so you need to manually destroy objects that you dynamically allocate. However, the way you've written your code, you've made that impossible.
You're dynamically allocating an object with new, which returns a pointer to the object. Then you are dereferencing that pointer (via *), and copying the object to vec. vec gets properly destroyed, but the dynamically allocated object that it was copied from does not. And since you didn't store that pointer, you're left with no way to access that object, and no way to dispose of it. In order to destroy that object, you would have had to capture the pointer, like this:
std::vector<int>* vec_pointer = new std::vector<int>();
Then later, you could call delete on the pointer, which destroys the object and deallocates the memory:
delete vec_pointer;
Thankfully, dynamic allocation is not a necessity as it often is in those other languages. Declaring an object creates it, and it is destroyed when it goes out of scope. So the simple line of code I showed you is sufficient, with no delete statement necessary.
As a side note, if you've determined, for some reason, that you must have dynamic allocation. Use a smart pointer (google that).
Your program is leaking memory.
std::vector<int> vec declares a vector on the stack. You create a second (empty) vector on the heap, and use it to copy-construct the one on the stack. Since it's empty, this effectively does nothing.
But, you've lost the pointer to the vector that was created on the heap (because you never stored it). So you can't delete it, and that memory can't be reclaimed. The vector on the stack, however, cleans up after itself just fine.
What you probably want is just:
std::vector<int> vec; // Vector on stack, no manual memory management required
If you really want to use the heap for some reason (the stack is faster, and vector object itself is of a small fixed size regardless of how many elements you put in it, so you don't have to worry about overflowing the stack), you can do:
// Declare pointer to vector, and initialize it with a new vector on the heap
std::vector<int>* vec = new std::vector<int>();
Or even (in C++11):
auto vec = new std::vector<int>();
Then, when you are done with it:
delete vec;