I have a struct that contains many variables of several types including vectors. Is it safe to store a pointer to the non-vector variables? I suspect when the vectors resize it is possible they will have to be moved to a different memory location. Does that also mean the rest of the variables may move?
I suspect when the vectors resize it is possible they will have to be moved to a different memory location. Does that also mean the rest of the variables may move?
std::vector does not store its elements inside the class. It stores them on the free-store and manages its own memory. Size of a class/struct is a constant expression and cannot change dynamically.
Is it safe to store a pointer to the non-vector variables?
Yes, of course. As long as the structure itself is valid, all pointers to its fields are also valid.
Is it safe to store a pointer to the non-vector variables?
Yes, as long as the struct itself doesn't move or gets destroyed (by leaving the scope or deleting it)
I suspect when the vectors resize it is possible they will have to be moved to a different memory location
You don't seem to understand how vectors work.
What you store in your struct is not the "vector" itself, but just information about it.
The actual data (i.e. your structs within the vector) are dynamically (re-)allocated on the free-store during runtime.
Side note:
If you know the size of the vector at compile time, you can use std::array, it has similar semantics like vector, but is an actual fixed-size array (changing array size changes sizeof the struct it is contained in.)
Related
Let's say I have a std::vector which is declared as static. Can I add objects, which are declared locally on the stack of a calling function to the vector without repercussions?
From my understanding, the vector stores its elements on the heap. Meaning if I tell the vector to MOVE the element like this
myvector.push_back(std::move(element));
it will be stored on the heap and its visibility will be preserved, right?
Edit: I would want to avoid the object from being copied because it manages other resources.
Am I correct? Or can this be done easier?
You generally can copy initialise objects with dynamic storage by copying from objects with automatic or static storage and vice versa. Whether the object is copied by moving does not matter.
There can in theory be classes that only work correctly when allocated in certain way, but such classes should be made non-copiable to prevent problems.
I came across with an issue with std::vector<T>, where T is a built-in type saying that the vector is not trivially copyable.
I was wondering if it's right and am looking for the reason.
Formally, a std::vector<T> (for any T) is not trivially copyable because its copy constructor is not trivial, if only because it's user-provided (as opposed to implicitly-defined).
Practically speaking, copying a vector involves more than making a shallow copy of its data members - it requires allocating a memory buffer on the heap and copying over its contents from another vector's heap-allocated buffer.
A vector grows as data is added to it. This means that one does not need to know upfront how much space is needed to store all its data. The vector solves this problem by allocating (and reallocating) a separate storage buffer on the heap. This buffer is managed internally while providing an interface that can be though of as a variably sized array.
Now if an object is trivially-constructable, one should be able to copy/clone the object simply using memcpy(dest, &a, sizeof(a)). If one were to do this for a vector, one would have 2 vector objects pointing to the same storage buffer. This will result in horrible undefined behaviour. Copying a vector therefore requires that one duplicate the internal storage, duplicate its parameters and then set the internal pointer to point to the correct storage buffer. This requires internal knowledge of the object to do.
std::array however, has a static size set at compile time. It does not have internal pointers and can therefore be copied simply by using memcpy. It therefore is trivial to copy.
Before I start, I have already looked at these questions:
Memory consumption of a pointer to vector of pointers
Pointer to vector vs vector of pointers vs pointer to vector of pointers
And they both do not answer my question.
I am working on a project where it involves millions of instances to work with.
The data structure I am using is a bit complicated to look at for the first time, the structure itself isn't really of any importance for this question.
Now, if I had the following:
vector<object*> *myVector;
Everything goes to the heap.
However, what happens if I used this:
vector<object*> myVector;
Does the vector itself get stored on the stack? And its contents are then stored on the heap? For example, if the vector had 10 million instances, would I have 10 million references on the stack for 10 million objects on the heap? Or am I missing something?
Moreover, if I used this:
vector<object> *myVector;
Where do the contents of the vector go? Does everything go on the heap? If yes, then does it work recursively? For example:
vector<vector<vector<int>>> *myVector;
Are all the inner vectors then stored on the heap? If yes, then it should be enough deleting myVector in the destructor, without worrying on anything else?
Anyway, I am assuming all the answers that apply to vector would also apply to unordered_map. Please tell me if I am wrong.
Thanks in advance.
In general, elements of a std::vector will always be dynamically allocated on the heap. For most implementations, a std::vector<T> foo, where T could be a pointer or not, there will always be three pointers on the stack that describe the vector itself, but not the elements. For a std::vector<T> *bar, there is one pointer, bar, on stack. The three vector pointers as well as the vector elements are on the heap.
Similarly, for an std::unordered_map, the elements itself will always be dynamically allocated on the heap. Generally, any std type that has a Allocator template parameter, or any type that contains a variable amount of data, will have it's data dynamically allocated on the heap.
Now there are special cases, like custom allocators, weird optimizations, specifics of terminology, but for practical purposes, this is what you should know.
The next thing that you might want to learn about, are smart pointers, e.g. std::unique_ptr, and std::shared_ptr, ownership semantics and RAII. That is actually more important to know in order to write correct code (What do I need to delete and worry about?).
Let's say I have a struct like this:
struct typeA
{
long first;
string second
double third;
};
If I declare
typeA myArray[100];
Then myArray is stored in the stack, consuming sizeof(typeA)*100 bytes of garbage data (until I store some actual data, at least).
Whenever I pass this array as a parameter, I'll always be passing a pointer to the first of the first element in the stack. So the pointer goes from stack to stack.
But if I declare
vector<int> myVector (4, 100);
Then the myVector object is actually stored in the stack, and it contains a pointer to the first element of an array of 4*sizeof(int) bytes stored in the heap, where the actual data is stored. So pointer goes from stack to heap.
Whenever I pass this vector as a parameter, if I add it to the parameter list like this:
vector<int> parameterVector
the function gets a copy of the myVector object and stores it in the stack.
But if I do it like this:
vector<int> ¶meterVector
the function gets a reference to myVector stored in the stack, so I now have a variable stored in the stack, referencing a myVector object also stored in the stack, that contains a pointer to an array of actual elements stored in the heap.
Is this correct?
I have a few doubts here:
Do the actual elements get stored in a static array (the ones inherited from C, indicated with square brackets) in the heap?
Does the myVector object have just one pointer to the first element, or it has multiple pointers to each one of the elements?
So passing a vector by value doesn't pose much of a problem, since the only thing that gets copied is the vector object, but not the actual elements. Is that so?
If I got the whole thing wrong and the actual elements are copied as well when passing a vector parameter by value, then why does C++ allow this, considering it discourages it with static arrays? (as far as I know, static arrays always get passed as a reference to the first element).
Thanks!
Do the actual elements get stored in a static array (the ones inherited from C, indicated with square brackets) in the heap?
Typically the elements of the vector are stored in the free store using a dynamic array like
some_type* some_name = new some_type[some_size]
Does the myVector object have just one pointer to the first element, or it has multiple pointers to each one of the elements?
Typically a vector will have a pointer to the first element, a size variable and a capacity. It could have more but these are implementation details and are not defined by the standard.
So passing a vector by value doesn't pose much of a problem, since the only thing that gets copied is the vector object, but not the actual elements. Is that so?
No. copying the vector is an O(N) operation as it has to copy each element of the vector. If it did not then you would have two vectors using the same underlying array and if one gets destroyed then it would delete the array out from under the other one.
Do the actual elements get stored in a static array (the ones inherited from C, indicated with square brackets) in the heap?
std::vector<> will allocate memory on the heap for all your elements, given, that you use the standard allocator. It will manage that memory and reallocate, when necessary. So no, there is no static array. It is more as you would handle a dynamic array in C, but without all the traps.
If you are looking for a modern replacement for C-Arrays, have a look at std::array<>. Be aware, that a std::array<> will copy all the elements as well. Pass by reference, if that is what you mean.
Does the myVector object have just one pointer to the first element, or it has multiple pointers to each one of the elements?
std::vector usually is a pointer to the first element, a size and a few more bits for internal usage. But the details are actually implementation specific.
So passing a vector by value doesn't pose much of a problem, since the only thing that gets copied is the vector object, but not the actual elements. Is that so?
No. Whenever the vector object gets copied to another vector object, all the elements will be copied.
If I got the whole thing wrong and the actual elements are copied as well when passing a vector parameter by value, then why does C++ allow this, considering it discourages it with static arrays? (as far as I know, static arrays always get passed as a reference to the first element).
The "static arrays" are a C-Legacy. You should simply not use them any more in new code. In case you want to pass a vector by reference, do so and nothing will be copied. In case you want the vector to be moved, move it, instead of copying it. Whenever you tell the compiler, you want to copy an object, it will.
OK, why is it that way?
The C-behavior is somehow inconsistent with the rest of the language. When you pass an int, it will be copied, when you pass a struct, it will be copied, when you pass a pointer, it will be copied, but when you pass an array, the array will not be copied, but a pointer to its first element.
So the C++ way is more consistent. Pass by value copies everything, pass by reference doesn't. With C++11 move constructors, objects can be passed by moving them. That means, that the original vector will be left empty, while the new one has taken over the responsibility for the original memory block.
I have a vector<some_struct&> array in my code, and whenever I want to add some object to my vector I use array.push_back(*new some_struct). now I'm wondering if I should delete every object in my array before clearing my array (using delete &array[i]) or not?
vector<some_struct&> array is invalid, period.
The type (or types) with which you instantiate a Standard Library container must be object types. A reference type (like some_struct&) is not an object type.
By definition, "containers are objects that store other objects" (from ยง23.1/1 in both C++03 and C++0x). References are not objects.
The behavior is undefined if you instantiate a container with a type that does not meet the requirements that the container imposes: your code may or may not compile and if it does compile, who knows what the result will be; anything could happen..
How does this even compile? That's not legal C++ code on any compiler I've used in the past 5 years.
The vector reference says that push_back copies the data to the container. In your example, not the pointer to, but the contents of each structure would be copied. So if you use *new my_struct, the reference to the memory allocated for the structs will be lost after having used them to pass the data to the container, meaning you need to store those pointers to each of the structs you allocated somewhere to be able to release them, or you will get memory leaks.
If you wanted to keep the pointers, the container should be a vector<some_struct*>, and you could pass new some_struct and should (e.g.) release them with delete array [i].
If your vector is declared vector<some_struct&> array, array.push_back(new some_struct) shouldn't work. array.push_back(some_struct()) will work and in that case you don't need to call delete.
You're going to lose the memory allocated every time you do this. You're essentially creating a copy of that data, but the original is lost in memory somewhere once this process completes. Either keep an external reference to it somewhere which you can delete after you copy it, or use a vector of pointers, not references.