c++ reference to a vector issues? - c++

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.

Related

How to create a pointer without creating an object from inside a parameter list

I need a vector of pointers to some preexisting objects, so I would like to create a pointer directly inside the vector.
I thought of calling the emplace_back function of my vector passing new as parameter, but this would not only create the pointer I want, but also an object. To get rid of this undesired collateral effect, I would do a delete pointer, which actually delete the object and leaves the pointer there, and then I would set this pointer to point to the preexisting object that I want. In code, it would be something similar to:
std::vector myVector<ClassType*>;
myVector.emplace_back(new ClassType());
delete myVector.end();
myVector.end()=&preexistingObject;
However, I think it's a waste to create an object just to delete it right after just because I want a pointer!
How can I create a pointer without creating an object in a way that I can create it from inside a parameter list (inside emplace_back in this case)?
I could write
ClassType *myPointer;
But the problem is that I cannot do it from inside emplace_back function as I need.
Any suggestions?
Thanks for your help,
Gustavo
The answer is to pass the address of the pre-existing object to my container as user4581301 suggested.
The only tricky point is that my software started crashing sometimes, and I have it tracked it to be a problem of pointers pointing to gargabe.
This happens because my pre-existing objects are stored inside a vector (std::vector), and when my vector got too big, all my pointers would get invalid, because... The vector changed the memory address of its contents when it has to make room for more items!
The solution is to store the pre-existing objects inside a list (std::list), which guarantess that my pre-existing objects won`t have their address changed when the list get too big.
To resume, in code, what I had to is:
std::list<PreExistingClass> myContainerOfObjects; //This HAS to be a list. Otherwise, dangling pointers!
std::vector<PreExistingClass*> myContainerOfPointerToObjects
myContainerOfObjects.emplace_back();
myContainerOfPointerToObjects.emplace_back(&(myContainerOfObjects.back()));
Thanks!
Gustavo

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

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.

Removing objects from C++ containers without deleting them

I am using C++ std vector to store render objects for a simple scene graph implementation.I need an ability to add and remove render objects in run time from the scene graph.Adding is not a problem,for removing: reading docs for vector and other C++ containers it appears that when objects are popped their destructors are called.That is not what I need because I want to be able to re-add those objects later to the rendering loop.What are the possible solution to this problem?
Important detail I forgot to mention -I am using vector of pointers to the render objects.
It seems you're confused with the basic concept of object instances. When you add something to a vector, you don't move it into it, you copy it:
vector<string> vec;
string s;
vec.push_back(s);
vec[0] is not s, it's a copy of s. So when you remove it from the vector, s is not affected.
If you don't want copies, you should switch to pointers instead. You can them remove the pointers from the vector and the destructor of the object they point to will not be called.
Edit:
OK, it seems you're already using pointers. You said:
reading docs for vector and other C++ containers it appears that when
objects are popped their destructors are called
That is true. When you remove a pointer from the vector, the pointer is getting destroyed. That's what the docs mean. It doesn't mean that the object the pointer points to is getting destroyed:
vector<string*> vec;
string s;
vec.push_back(&s);
vec.pop_back();
s is not affected at all. What gets destroyed by the pop operation is the pointer that holds the address of s, not s itself.
So you're fine.
You need to be aware of ownership to make this work correctly. If the vector you are using is only temporary and only to observe objects, just use a vector of points.
std::vector<object*> x;
On destruction of that vector the objects that are being pointed to are unaffected.
If you want to share ownership, use a boost::shared_ptr or std::shared_ptr.
When a pointer is popped, no destructor is called. Notionally even primitive types have destructors, to explain what happens when they go out of scope. Destroying a vector of pointers is the same as having a bunch of local pointer variables go out of scope.
Reference-counted smart pointers are objects that overload the * and -> operators to behave like pointers. They do implement the destructor to destroy the pointed-to object, thus implementing ownership. But for a scene graph, that's probably unnecessary.

When adding an element to a vector, how to know that a copy of the object is going to be made?

I have an object called LastQueryInfo lastQuery in my class. Every time this object changes, I add it to a vector called history.
Initially, when I did history.push_back(lastQuery) I didn't know what would happen - is the vector going to make a copy of the object? or is it going to keep a reference to it? So if later I modify lastQuery, are all the objects (assuming they are references) in the history vector going to be modified?
After some testing, I found that history.push_back(lastQuery) is indeed going to make a copy of the object, then add it to the vector. But how can I know that without doing any tests? How can I know when C++ is going to make a copy, and when it's going to add the actual object?
std::vector always stores a copy† of whatever you push_back(). So modifying the value you passed in will not affect the value stored in the vector. It isn't like Java or C# where an Object o; is actually a reference to the object, and the object lives until the garbage collector comes and picks it up when the last reference to it goes away. In C++, Object o; is the actual object, which will go away at the end of its scope.
So if std::vector only stores references to the objects you push_back(), then it will be utterly useless for things like this:
std::vector<int> numbers;
for(/* loop condition */) {
int number = GetUserInput();
numbers.push_back(n);
}
Since number will go away at the end of the loop, numbers would hold references to something that will not exist if std::vector was implemented by storing only references. If std::vector actually stored the values, you could access them even after the loop.
† C++11 supports move semantics, so if the thing you're pushing back is actually a temporary that will go away soon, it'll move the internals of the object into the vector storage instead of copying. You can also explicitly use C++11's std::move() to "force" the move during push_back(). But vector will copy the value in every other case. It's an implementation detail to optimize the performance of vectors.
Using push_back will always create a copy of the object that is being stored.
If you are using c++11, then there are two ways to avoid the copy :
use the emplace method
move the created object into the vector: vec.push_back( std::move( obj ) );
If you are not using c++11, then the only thing you can do is to use pointers or boost::shared_ptr as vector types.

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.