C++ vector passed by value: did I get it right? - c++

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> &parameterVector
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.

Related

Struct memory locations of member variables

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.)

std::vector vs dynamic array passing by value

Hello I am comming from c to c++ and I've been wondering why can std::vector be passed by value.
I assume passing dynamicaly allocated array by value is not possible as that would only copy the pointer.
How is it then possible for a vector to be coppied, if inside of a vector class is same pointer. It has to somehow know how to reconstruct it into another object.
std::vector knows how many elements are stored in the dynamic memory. It is a simple matter to allocate a new buffer of that size and copy the contents into that new memory. All of this happens in the copy constructor.

c++ vector of pointers push back in different way

First we have a vector of pointers as:
vehicleGroup<vehicle*> VG;
In c++, is there a difference between:
VG.push_back(new vehicle(1));
VG.push_back(new vehicle(2));
and
//tmp_vehicle is a public class member
tmp_vehicle = new vehicle(1);
VG.push_back(tmp_vehicle);
tmp_vehicle = new vehicle(2);
VG.push_back(tmp_vehicle);
Does the vecotr VG contains the address of pointer itself OR the address the pointer pointed to?
What about map?
VG contains exactly what you ask it for - pointers to vehicle objects.
When you call push_back(), it takes object you provided (in your case "object" is vector*), makes copy of it and puts it to vector. Vector uses internal memory chunk where it stores objects, so that's why it needs to make copies.
The two versions do the same thing.
In your second version, tmp_vehicle first points to whatever new vehicule(1) returned. This pointer is then pushed into the vector, so the vector's first element now also points to that location.
Seen another way, you're not storing tmp_vehicule itself in the vector. You're storing a copy of that pointer.
Then you make tmp_vehicule point to something else. This doesn't change the fact that you stored a pointer to the first location in the vector. It changes what your variable points to, but doesn't change the vector in any way.
(And if you hadn't stored that pointer in the vector, you'd have a memory leak after the second assignment to tmp_vector, since you'd have lost all pointers to the first vehicule - so no way to delete it.)

c++ reference to a vector issues?

Im having some difficulties when passing a reference to a vector as an argument. Initially it was a pointer to a vector of pointers, and the functions called would change attributes of whatever obejct was calling it. For example I used:
(*myVector)[i]->myFunction();
and everything worked perfectly. myFunction() would translate whichever object was the current index of myVector.
Now i've changed the vector to hold a set of objects instead of pointers to the objects as it did originally. Instead of passing a pointer to the vector, i pass a reference of it. I access the function as follows:
myVector[i].myFunction();
It compiles, I find that myFunction() no longer has the same results as it did before. I used a breakpoint and saw that it was changing attributes it should have been, however, those changes never made it to the original object. There was no final translation even though the breakpoint showed the origin of myVector[i] being changed.
I've tried passing a pointer to the vector of objects and used:
(*myVector)[i].myFunction();
and the same thing, it compiled but didn't work.
Finally i tried simply passing a reference to the first object in the vector, and of course that worked just fine:
myObject.myFunction();
Is there some inherent thing im missing about references of vectors? Why does a pointer to a vector of pointers work but a reference to a vector of objects doesnt? Shouldn't the passed vector be an alias to the original vector? Why is the reference showing changes but not the object it referenced?
Why wont my changes stick unless i used a vector of pointers instead of a vector of objects.
Hold on a minute. When you changed this snippet:
(*myVector)[i]->myFunction()
To this:
myVector[i].myFunction()
You've actually changed two things:
myVector went from pointer to reference;
The type of the elements inside myVector went from pointer to simple value type.
If you changed the type of the elements to a simple value type (as in std::vector<int*> to std::vector<int>), then when you add them to your vector, they are copied to it. (The way the vector is passed around, that is, by pointer or by reference, doesn't affect this behavior. The way the vector is passed and the way the objects inside the vector are passed are completely independent.) This mean that whenever you make a change to them, you only change the version that's inside the vector.
There's nothing wrong with using a vector that holds pointers (as long as you do your memory management in a sensible way). If you want the changes to the version you have in your vector to be replicated to the originals, you'll have to use references or pointers. Since it's a world of pain to have a vector contain references (as in std::vector<int&>), if at all possible, you would probably prefer pointers.
If your changes aren't making it into the "original" object it sounds like you passed by value somewhere. Here are some ideas. Perhaps you can post some more code?
Did you put copies of the objects into the vector, and expect the originals to be modified?
The problem could be that your objects' copy constructor doesn't copy all the members. Is the vector growing? If objects are being moved around inside the vector, it's critical to get the copy constructor working.
Finally:
Keeping a vector full of pointers, or smart pointers that are container safe, is usually a better fit than a vector of objects, because it avoids unnecessary copying and destructing. Unless the objects are very small (like a Date class with one data member) I wouldn't put them into a vector, I'd use smart pointers.
It shouldn't matter here whether you pass a pointer to a vector, or a reference to a vector. Conceptually they are different (references can't be null, for one), but in the implementation they are both pointers to the vector, and the vector isn't passed by value.
The problem has nothing to do with whether you hold a pointer or a reference to the vector. It has to do with what the vector contains. If the vector contains pointers, then when you change the pointed-to objects in the vector, whatever other pointers or references exist for the same objects will be affected as well. But if your vector contains objects (by value), you are copying them when you insert, and changes inside the vector won't be seen outside, nor vice versa.
This is the fundamental nature of pointers and references--if it doesn't make sense, you should look for a decent book on C++.
When a vector stores objects, it stores a copy of the original object that was passed in. So when you do something like this
yourClass yourObj;
std::vector<yourClass> yourVector;
yourvector.push_back(yourObj);
yourvector[0].myFunction();
only the object at yourvector[0] changes because it is a copy of the original.

c++ vector of class object pointers

What I am trying to do is essentially create two vectors of objects, where some objects are entered into both lists and some are just entered into one. The first problem I found was that when I used push_back() to add an object into both lists the object was copied so that when I changed it from one list the object did not change in the other. To get around this I tried to create a list of pointers to objects as one of the lists. However when I accessed the pointer later on the data seemed to be corrupted, the data member values were all wrong. Here are some snippets of my code:
Definition of vectors:
vector<AbsorbMesh> meshList;
vector<AbsorbMesh*> absorbList;
...
Adding an object to both:
AbsorbMesh nurbsMesh = nurbs.CreateMesh(uStride, vStride);
// Add to the absorption list
absorbList.push_back(&nurbsMesh);
// Store the mesh in the scene list
meshList.push_back(nurbsMesh);
Accessing the object:
if (absorbList.size() > 0)
{
float receivedPower = absorbList[0]->receivedPower;
}
What am I doing wrong?
There's some details missing, but at a guess.
nurbsMesh goes out of scope between the push_back and the absorbList[0]->receivedPower.
So now your vector of pointers contains a pointer to an object that doesn't exist anymore.
Try adding a copy constructor to your AbsorbMesh class and adding to your vector like this.
absorbList.push_back(new AbsorbMesh(nurbsMesh));
meshList.push_back(nurbsMesh);
don't forget to delete the objects in absorbList, like this
for(vector<AbsorbMesh*>::iterator it = absorbList.begin(); it != absorbList.end(); it++) {
delete it;
}
Or store a shared pointer in your vector instead of a bare pointer. Boost has a good shared pointer implementation if you're interested. See the docs here
If you want to have updates to items in one vector modify objects in the other vector, then you'll need to store pointers in both vectors.
Using your original requirements (updating an item in one vector affects items in the other vector, here's how I'd do it with a boost shared pointer. (WARNING, untested code)
vector<boost::shared_ptr<AbsorbMesh> > meshList;
vector<boost::shared_ptr<AbsorbMesh> > absorbList;
boost::shared_ptr<AbsorbMesh> nurb = new AbsorbMesh(nurbs.CreateMesh(uStride, vStride));
meshList.push_back(nurb);
absorbList.push_back(nurb);
...
...
if (absorbList.size() > 0)
{
float receivedPower = absorbList[0].get()->receivedPower;
}
You are storing the address of an object allocated on stack. The nurbsMesh object gets destroyed as soon as your method which does push_back() ends. If you try to access this pointer afterwards the object is already destroyed and contains garbage. What you need is to retain the object which remains even after the function goes out of scope. To do this allocate the memory for the object from heap using new. But for every new you should have a corresponding delete. But in your case you'll have problems deleting it as you are pushing the same pointer into two vectors. To solve this, you would require some type reference counting mechanism.
Object is deleted when you try get pointer from vector.
Try do
vector.push_back(new Object);
Once you have fixed the problem that others mentioned (storing a pointer to an object that's on the stack), you're going to run into another issue. A vector may reallocate, which results in its contents moving to another location.
The safe way to do this, then, is to store pointers in both vectors. Then, of course, you need to ensure that they get deleted... but that's C++ for you.
absorbList.push_back(&nurbsMesh); is wrong
absorbList save pointer to local object. When nurbMesh is destroyed you can not write
absorbList[0]->
However when I accessed the pointer later on the data seemed to be corrupted
When you put something on a vector, the vector might move it from one physical location to another (especially e.g. when the vector is resized), which invalidates any pointer to that object.
To fix that, you'll need to store a pointer (possibly a 'smart pointer') in both vectors (instead of having one vector contain the object by value).
If you're going to do this, it might be a good idea to disable the object's copy constructor and assignment operator (by declaring them as private, and not defining them) to ensure that after an object is created it cannot be moved.
There are several things wrong with your example
AbsorbMesh nurbsMesh = nurbs.CreateMesh(uStride, vStride);
This object is allocated on the stack. It is a purely local object. This object is going to be destroyed when you reach the end of the current block surrounded by {}.
absorbList.push_back(&nurbsMesh);
Now you get the pointer to the object that most likely will be destroyed.
meshList.push_back(nurbsMesh)
And this copies an entirely new object on the vector.
It is equally wrong to push the object on the vector first and then push a pointer to the object on the vector using absorbList.push_back( &meshList.back() ) because vector::push_back will reallocate the whole vector, invalidating all pointers.
You might be able to create all AbsorbMesh objects first, push them onto a vector, and then get the pointers to these objects in the vector. As long as you don't touch the vector, you'll be fine.
Alternatively, create objects on the heap using new AbsorbMesh() but make sure to call delete on each pointer thus created. Otherwise you have a memory leak.
Third solution, avoid the trouble and use smart pointers that take care of object destruction for you.
First, as everybody else points out, you can't allocate objects on the stack (i.e., other than by new or something similar), and have them around after leaving the scope.
Second, having objects in an STL container and maintaining pointers to them is tricky, since containers can move things around. It's usually a bad idea.
Third, auto_ptr<> simply doesn't work in STL containers, since auto_ptrs can't be copied.
Pointers to independently allocated objects work, but deleting them at the right time is tricky.
What will probably work best is shared_ptr<>. Make each vector a vector<shared_ptr<AbsorbMesh> >, allocate through new, and at a slight cost in performance you avoid a whole lot of hassle.