deleting a vector of pointers vs. object in c++ - 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.

Related

Pointer to std::vector

So here is the problem I am having.
I have a pointer to std::vector. So after I initialize the pointer, I don't add any items to the vector, nor remove any. However, at a certain point in my code, my std::vector moves locations, and I end up with a dangling pointer. This seems to happen randomly, even though I never touch the vector after making the pointer
It took me a while debugging this, to figure this problem out. Is there a way to guarantee that my std::vector will not change memory locations? Or is it just a bad idea to have a pointer to a vector.
Or is it just a bad idea to have a pointer to a vector?
In general, I would say it is a bad idea to have raw pointers for controlling an object's lifetime. Don't use raw pointers and automatic memory management, try using smart pointers with the appropriate ownership semantics (std::shared_ptr<> or std::unique_ptr<>). Use raw pointers only for observing pointers (and if you want to be able to verify at run-time whether they are dangling, use weak_ptr<>).
Also, in many cases you may realize you do not need a pointer at all. In that case, just use an object with automatic storage, which can be efficiently moved around or passed/returned by value in C++11 thanks to move semantics.
This seems to happen randomly
No, it doesn't. As long as it stays in scope it has the same address. What is probably happening is that the vector is going out of scope, and since it was automatically allocated (sounds like) it is getting destroyed at that time. What you can do is allocate the vector on the heap (for e.g. ints):
std::vector<int>* pv = new std::vector<int>();
Then you will not have this problem. However you must remember to explicitly delete it with
delete vp;
before pv goes out of scope or you'll get a memory leak.

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

Creating an object on the stack then passing by reference to another method in C++

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

Memory management with new keyword and an STL vector of pointers

How is the destructor for the vector managed when adding elements to this list? Is the object destroyed correctly when it goes out of scope? Are there cases where it would not delete the object correctly? For example what are the consequences if "table" was a child of object, and we added a new table to a vector of object pointers?
vector <object*> _objectList;
_objectList.PushBack(new object);
Since you're making a vector of "bare" pointers, C++ can't possibly know that the pointers in question are meant to have "ownership" of the objects they point to, and so it will not call those objects' destructors when the pointer goes away. You should use a simple "smart" pointer instead of a "bare" pointer as the vector's item. For example, Boost's shared_ptr would be perfectly adequate for the task (although you can surely do it with "cheaper", lighter-weight approaches, if you don't want to deal with Boost as a whole and have no other need for smart pointers in your code).
Edit: since you (the OP) say that using a framework such as Boost is not feasible, and a couple comments usefully point out that even wrapping std::auto_ptr doesn't really qualify as a decent shortcut, you may have to implement your own smart pointers (or, if you find an open-source, stand-alone smart pointer template class that looks usable, audit it for compliance with your requirements). This article is a useful primer to smart pointers in C++, whether you have to roll your own or audit an existing implementation.
You could use bost 'ptr_vector'. It will automatically destruct objects that the items point to when they are either deleted or the instance of ptr_vector goes out of scope. More info is available here.
In your case, the object pointers are destroyed properly, but the actual objects themselves won't be touched. The STL properly destructs all contained elements - but will not implicitly dereference pointers to types.
STL Vectors make a copy of whatever you put in there, and ultimately delete that copy.
So in this case, the vector is storing a pointer to an object - not the object itself. So it makes a copy of the pointer, and deletes the pointer. But, as Chris said, the object itself will not be deleted.
So, solutions:
If you don't really need to use pointers, then don't:
vector <object> _objectList;
_objectList.PushBack(object());
If you do need to use pointers, you can either use a smart pointer (which handles reference counting for you, and will delete the object along with the pointer), as Alex suggested, or use a ptr_vector, as Igor mentioned.

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.