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.)
Related
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
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.
So I'm trying to implement some memory management techniques here. In my program, I created an stl list so that it would contain objects of the class "Blast" with it's respective iterator:
list<Blast> blasts;
list<Blast>::iterator it1;
I've looked around and found that if you use the erase function, it will call the destructor of the class, and then delete the iterator to which it points to the object and return some other pointer (iterator). However, if the class is a POD, then the call for the destructor won't do anything, hence all the information that was saved in that object will be kept in memory.
To go around this, I tried to allocate the object dynamically so that I could use the delete function to wipe it out of memory as such:
Blast *blast;
blast = new Blast;
However, here I encountered a problem. When i tried to push the object onto the list, it only lets me push the pointer:
blasts.push_back(*blast);
At first, I didn't think anything about it. So I continued:
if(it2->getX() > 600) {
delete &it2;
it2 = blasts.erase(it2);
}
I realized then, that what this does is that it erases the pointer that was pointing to the object, and then the pointer that was pointing to the pointer pointing to the object.
I'm not entirely sure if that is actually correct, as I have no way of knowing if there's a memory leak. So my question is this:
What do I have to do to erase the object from memory BEFORE deleting whatever pointer is pointing to that object? Is my implementation correct? Is it's result the same as if I were to just simply push the object onto the list?
then delete the iterator to which it points to the object and return some other pointer (iterator)
Not a pointer, an iterator.
hence all the information that was saved in that object will be kept in memory.
No, that's not true.
When i tried to push the object onto the list, it only lets me push the pointer:
Huh? If you have a std::list<Blast> then of course you can't store a Blast* in the list, that's not the same type. Maybe you want to change the list to a std::list<Blast*>?
delete &it2;
This is wrong, it tries to delete the iterator, not the list element it refers to. To delete the element it points to you want:
delete &*it2;
But if you still have a std::list<Blast> then that will try to delete an object owned by the list, which would be very wrong and cause bugs.
I think you should just stick to std::list<Blast> and forget this entire question - it seems to be based on a misunderstanding that erasing an element doesn't destroy the object, which is not true. If your problem is that Blast objects have pointer members that point to dynamically allocated memory then add a destructor to Blast to make it clean up properly.
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.
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.