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.
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
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.
I am using vector as a buffer to store some objects to be later appended to another vector.
std::vector<Link*> buffer_vector;
std::vector<Link*> main_vector;
main_vector.insert(main_vector.end(),buffer_vector.begin(),buffer_vector.end());
The process of filling the buffer and appending occurs repeatedly. Therefore I need to clear the buffer at every iteration. My concern is if I use .erase or .clear methods to clear the buffer, the objects in the main vector will be deleted. Is this assumption correct?
If yes, is there a workaround for that?
Thank you
vahid
Your concern is incorrect.
main_vector.insert(main_vector.end(),buffer_vector.begin(),buffer_vector.end()); copies the elements from buffer_vector into main_vector.
These copied elements are totally separate from the original elements, and so they are not affected by modifications to the elements that they were copied from.
If you mean clearing the buffer_vector will clear the contents in main_vector, no they are separate copies.
Insertion into a vector is done by copy. In other words, you're pushing a copy of the element into the new vector. A different copy will be deleted when the buffer vector is cleared.
(This assumes that you're pushing the same type into both vectors, and not something like a pointer to an element to a vector in the first vector into the second vector.)
You are copying the elements into the vector, and they will stay there until you delete them.
In the code you show, you are storing pointers into objects. The pointers will be copied, and nothing will happen to the allocated memory when the original vector is cleared or the elements erased.
Actually nothing will happen to the pointed memory when the second vector goes out of scope!! Your program leaks memory, you need to manually manage the pointers or else choose an appropriate smart pointer that you can use inside a vector (consider std::unique_ptr or std::shared_ptr from C++11 or the equivalents from boost or TR1).
You may be confused about how a vector manages its objects. When you push_back into a vector, you make a copy. When you push_back a pointer, it copies the pointer. When you call clear() or erase() it deletes the pointer but not the object the pointer points to.
I am assuming you new'ed all your Link objects and added them to the vector container. You will need to delete them yourself, the container will not destroy the pointed to object for you (even if the container itself is destroyed when it goes out of scope). If you clear() both your containers before calling delete on all your Link objects, you will cause a memory leak (assuming you are not keeping pointers to Link objects somewhere else).
I have a vector of pointers to an object (I have them as pointers because I will be swamping the positions around a lot, and I would imagine it would be a lot faster to just swap the pointer, rather than swapping around the whole object.
Anyway, I will ultimately need to delete the vector, but the objects that it points to still need to be valid. The documentation seems to say that it will call the destructor on every object in the vector. This makes sense when it's an array of objects, but if the array is an array of pointers to objects, will the objects that the pointers point to also be deleted, or do I need to delete them manually?
If they are deleted automatically, is the only way to keep the objects around (say they were used in a different vector) is to actually copy the objects to another location, and have the pointers in the vector point to those objects (rather than the originals)?
Thank you.
Calling a destructor on a pointer value does nothing. (On the other hand, calling delete on a pointer value runs the destructor for the pointed-to object, and frees the memory.)
In the case of an array of pointers to objects, you must free the objects manually if that's what you want.
If you have a vector of pointers, the actual objects should still be around if you delete (or clear) the vector.
You could use smart pointers in your vector, such as Boost shared_ptr.
It will indeed destruct any objects in the container. However, since all the objects in your container are pointers, that won't do much of anything.
Reading your question, that sounds like exactly what you want it to do, so you are good.
It does not matter - that's the reason for the delete keyword. If you go out of scope, then the object's destructor is called. If a pointer goes out of scope, then it tends to be a memory leak. The same applies here, so you will not have to do anything special.
They will continue to exist.
Anyway, I will ultimately need to delete the vector, but the objects that it points to still need to be valid. The documentation seems to say that it will call the destructor on every object in the vector. This makes sense when it's an array of objects, but if the array is an array of pointers to objects, will the objects that the pointers point to also be deleted, or do I need to delete them manually?
First, read this: http://crazyeddiecpp.blogspot.com/2010/12/pet-peeve.html
Now ask yourself, does the documentation say that vector deletes every object that every object it contains points at?
If you can answer that question with 'No' then there you have it.
If you can answer that question with 'Yes'...well...try different documentation.
I am coming from a C# background to C++. Say I have a method that creates a object in a method on the stack, then I pass it to another classes method which adds it to a memeber vector.
void DoStuff()
{
SimpleObj so = SimpleObj("Data", 4);
memobj.Add(so);
}
//In memobj
void Add(SimpleObj& so)
{
memVec.push_back(so); //boost::ptr_vector object
}
Here are my questions:
Once the DoStuff methods ends will the so go out of scope and be popped from the stack?
memVec has a pointer to so but it got popped what happens here?
Whats the correct way to pass stack objects to methods that will store them as pointers?
I realise these are probably obvious to a C++ programmer with some expereince.
Mark
Yes.
The pointer remains "alive", but points to a no-longer-existent object. This means that the first time you try to dereference such pointer you'll go in undefined behavior (likely your program will crash, or, worse, will continue to run giving "strange" results).
You simply don't do that if you want to keep them after the function returned. That's why heap allocation and containers which store copies of objects are used.
The simplest way to achieve what you are trying to do would be to store a copy of the objects in a normal STL container (e.g. std::vector). If such objects are heavyweight and costly to copy around, you may want to allocate them on the heap store them in a container of adequate smart pointers, e.g. boost::shared_ptr (see the example in #Space_C0wb0y's answer).
Another possibility is to use the boost::ptr_vector in association with boost::ptr_vector_owner; this last class takes care of "owning" the objects stored in the associated ptr_vector, and deleting all the pointers when it goes out of scope. For more information on ptr_vector and ptr_vector_owner, you may want to have a look at this article.
To achieve your goal, you should use a shared_ptr:
void DoStuff()
{
boost::shared_ptr<SimpleObj> so(new SimpleObj("Data", 4));
memobj.Add(so);
}
//In memobj
void Add(boost::shared_ptr<SimpleObj> so)
{
memVec.push_back(so); // std::vector<boost::shared_ptr<SimpleObj> > memVec;
}
Yes your so object will be popped off the stack once your function leaves scope. You should create a heap object using new and add a pointer to that in your vector.
As said before, the pointer in your vector will point to something undefined once your first function goes out of scope
That code won't compile because inside the Add function you're trying to trying to push a whole object into a vector that expects a pointer to an object.
If instead you were to take the address of that object and push that onto the vector, then it would be dangerous as the original object would soon be popped off the stack and the pointer you stored would be pointing to uninitialised memory.
If you were using a normal vector instead of a pointer vector then the push_back call would be copying the whole object rather than the pointer and thus it would be safe. However, this is not necessarily efficient, and the 'copy everything' approach is probably not intuitive to someone from the C#, Java, or Python worlds.
In order to store a pointer to an object it must be created with new. Otherwise it will disappear when going out of scope.
The easiest solution to your problem as presented here would be to use std::vector instead of boost::ptr_vector, because this way the push_back would copy the object in the vector