Removing objects from C++ containers without deleting them - c++

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.

Related

Shared Pointer to an object in a vector

I'm trying to figure out, what happens if you create a shared pointer, that points to an object that is held in a vector.
The Code looks like this:
class TestObject
{
public:
int someTestData;
};
class Test
{
public:
std::shared_ptr<TestObject> testPointer;
std::shared_ptr<std::vector<TestObject>> getTestVector()
{
return testVector;
}
private:
std::shared_ptr<std::vector<TestObject>> testVector;
};
The Problem is, that I want to both support fast iteration over all TestObjects, but also provide shared pointers to single objects in the vector.
But now I dont know what happens if the last shared ptr to an object in the vector gets deleted.
Does the object get removed from the vector?
Does this cause undefined behaviour?
How can I archieve the behaviour I want if this doesnt work?
EDIT:
To Clarify, what i need:
I need a MemoryManager Class, that has a method CreateTestObject, that creates a new TestObject, stores it in a vector or some other container that supports fast iteration and returns a some kind of shared_ptr to the newly created object so that the object that needs a new TestObject has a reference.
Now i also need the shared_ptr to the TestObject to be able to remove the TestObject from the container it is stored in, when the last shared_ptr goes out of scope, so that i'm not left with a vector full of unused TestObjects.
It's hard to know what happens on your end, since you didn't share the code which actually initializes testPointer. But what you're looking for is an aliased std::shared_ptr:
testPointer = {testVector, &(*testVector)[0]};
From then on, testPointer points to the first element of the vector, but shares the ownership of the vector itself with testVector, providing the correct semantics.
Do note that this doesn't prevent the vector from relocating its storage and making testPointer dangle if you cause it to reallocate.
For the record, trying to construct a std::shared_ptr owning the element itself, as follows:
testPointer.reset(&(*testVector)[0]); // Wrong!
... will necessarily trigger UB down the line, since std::vector has unique ownership of its elements already, and there's no way that you can make std::vector or std::shared_ptr relinquish ownership.
"I'm trying to figure out, what happens if you create a shared pointer, that points to an object that is held in a vector."
That is a very bad idea because the position of any element of a vector can change simply by adding or removing an element to the vector. What you implement is simply a duplication of ownership which brakes basic OOP concepts.
Does the object get removed from the vector?
A shared pointer is the "owner" of the object and the vector is also the owner. So it is conceptional broken!
Does this cause undefined behaviour?
It is still undefined, as you generate dangling pointes because vector can move its objects.
How can I achieve the behaviour I want if this doesnt work?
You have already fast access via operator[] and you have already "pointers" as iterators can be used as any other pointer.
You can do this using a custom deleter with your shared_ptr and using a container like boost::stable_vector:
testVector.emplace_back();
auto it = V.end()-1;
auto deleter = [&testVector, it] (int*) {testVector.erase(it);};
std::shared_ptr<TestObject> ptr(&testVector.back(), deleter);
When the last shared_ptr to an object goes out of scope, it will remove it from TestVector. Note however, that this does not work the other way round: If the object is removed from TestVector through any other means (e.g. by TestVector going out of scope), this will trigger undefined behavior, so it is your responsibility to make sure that this does not happen. Note also that this does not work with std::vector, as the iterators get invalidated when the vector is resized. You could however use std::list, although that will probably be slower than stable_vector.
This is not the cleanest solution (due to the very real possibility of triggering UB if you're not careful), but doing this proberly would be much more involved.

vector of pointer

I just wonder what's wrong with vector of pointer. some of my friend recommend me to use list instead of vector. will this cause a problem:
vector<Fruit*> basket;
basket.push_back(new Apple());
basket.push_back(new Orange());
vector<Fruit*> temp;
temp.push_back(basket[1]);
If I delete vector temp, do I destroy the basket[1] object too? if not, what's the problem with using vector of pointer?
If I delete vector temp, do I destroy the basket[1] object too?
No. First of all, you cannot delete temp; rather, it will get destroyed when going out of scope. And when this happens, the objects pointed by elements of the vector won't be automatically deleted.
This is, however, not a specific problem of vector: using list will not save you from this issue. The problem is rather with raw pointers. If you want the pointed objects to be automatically deallocated when the the lifetime of the last pointer which points to it ends, you should use smart pointers.
Depending on the ownership policy that your application needs, you might choose between shared_ptr and unique_ptr. The caveat with shared_ptr is that referencing cycles shall be avoided, to prevent mutually referencing objects from keeping each other alive. You may want to check weak_ptr in this respect.
Finally, unless you have a good reason for not using vector, vector should be the default choice for a container. From Paragraph 23.2.3/2 of the C++11 Standard:
The sequence containers offer the programmer different complexity trade-offs and should be used accordingly. vector or array is the type of sequence container that should be used by default. list or forward_list should be used when there are frequent insertions and deletions from the middle of the sequence. deque is the data structure of choice when most insertions and deletions take place at the beginning or at the end of the sequence.
If either of the vectors, basket or temp, are destroyed none of the Fruits are destroyed. Anything that is dynamically allocated with new must be deleted. When the vectors go out of scope, they do not delete the objects that are pointed to by their elements. If you delete an object through one vector that is pointed to in the other vector, both point at the now deleted object.
Since your vectors have automatic storage duration, you definitely must not do delete basket; or delete temp;.
It's not recommended to use raw pointers in general, especially with dynamically allocated storage that you may forget to delete. In this case, however, you do need polymorphic behaviour, which is provided by pointers. You should use a smart pointer to avoid the problems with raw pointers. Try a std::vector<std::shared_ptr<Fruit>>.

deleting a vector of pointers vs. object in c++

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.

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.

Removing from STL std::queue without destructing the removed object?

All the documentation I can find on the STL containers (both queue and list) say that for any of the remove functions the removed object's destructor is called. This means that I can't use std::queue any time I want a queue that's simply a list of objects needing some operation performed on them.
I want to be able to add objects to the queue when they are waiting in line for me to do something to them. Then I want to remove them from it when I've finished with them, without destroying the object in question. This doesn't appear to be possible from the documentation I've read. Am I misreading the documentation? Is there another type of queue in the STL other than the basic "queue" that doesn't call the removed object's destructor on a call to pop_front?
Edit to clarify: In my case I'm using a list of pointers. Something like this:
dbObject *someObject;
queue<dbObject *> inputQueue;
inputQueue.push_back(someObject);
...
dbObject *objectWithInput = inputQueue.front();
//handle object's input...
inputQueue.pop_front(); // Remove from queue... destroyed now?
If you put pointers to objects in the queue (and any other STL container), the pointers won't get deleted when you remove them.
To elaborate: when you use std::queue and remove an object the destructor of some_obj* is called. But the destructor for plain pointer (or any POD type - int, char, etc) is empty, no-op. The fine line here is that the destructor for some_obj* is very different from the destructor for some_obj.
STL containers have value semantics. When you push an object into an STL container, the STL container keeps it's own copy of the object, and when the object (internal copy) is removed from the container it is destroyed.
If you used a container of a proxy type, as raw pointers, smart pointers (shared_ptr, weak_ptr), or adapters (as boost::reference_wrapper), then the STL container will destroy the proxy but not the type. Choosing one over the others is usually a matter of how you want to deal with resources.
The most common idiom is using raw pointers, but they don't explicit who is in charge of destruction (the code that pulls from the container should delete the pointer, or the resource is handled somewhere else?).
Modern usage moves towards the shared_ptr approach, as it dilutes the ownership problem. The object will be guaranteed to be alive when you take it out of the container, and if nobody else holds a shared_ptr then the object will automatically be deleted when the local shared_ptr goes out of scope. Using a weak_ptr will keep the ownership in the original code, but will allow you to check for validity of the pointer (if it was deleted) before usage. This could allow you to avoid performing the operation on an object that will be removed right away.
The problem with the shared_ptr/weak_ptr approach is that it forces you to use shared_ptr to hold the original resource. This means that you will not be able to put a pointer into a subobject (member attribute) of another class without redesigning the class to hold the attribute through a shared_ptr, and that will have other implications (the attributes will no longer be contiguous in memory, more dynamic allocation operations will be required...)
A technique that is hardly seen is using adapters as boost::reference_wrapper<>. A reference wrapper is a proxy object that contains a reference to the original object and is itself copyable. The advantage over plain raw pointers is that reading the code it is clear that the resource is managed outside of the queue: the code that pulls data from the queue does not need to delete the object. The advantage over the smart pointer approach is that you do not need to redesign other parts of your system to use smart pointers. The disadvantage is that, as in the raw pointer approach, you must ensure that the lifetime of the referred object outlives the reference in the container manually.
class someobj_t {};
std::queue<someobj_t> q;
...
someobj_t ppd = q.front(); // ppd is not a reference
q.pop();
// ppd now contain removed object
If you don't want someobj_t to be copied you could use std::queue< shared_ptr<someobj_t> >.
How about using a list of pointers to the objects?
Think of item's in a container being "in-scope" of that container, when an item is removed from a container it is just like leaving the scope of a function. If the variable is a pointer nothing happens to the item when leaving the scope. If variable is a stack local then destructor will will be automatically called upon leaving the scope.
Storing pointers in containers have the same downfalls as allocating into a local raw pointer, the memory is not cleaned up automatically. In a function if you don't delete the pointer or transfer ownership by returning it then you have a memory leak.
When storing raw pointers in a container the ownership can become a bit ambiguous and leaks can easily happen. Take a look at tr1::shared_ptr and store those in the containers instead.
std::unique_ptr in C++0x would also be a good solution for storing a pointer in a stdlib container when it is available.