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>>.
Related
In my code I have a vector of pointers to objects of SomeClass and a (custom comparison) vector-based priority queue that contains pointers to objects of SomeClass:
std::vector<SomeClass*> my_vector;
std::priority_queue<SomeClass*, vector<SomeClass*>, CustomCompare> my_queue;
Initially my_vector is empty and my_queue is full. Gradually my_queue is emptied into my_vector like this:
my_vector.push_back(my_queue.top());
my_queue.pop();
My question is: Will my_queue.pop() delete the memory that was allocated to the SomeClass object that was pushed back to my_vector therefore causing the element of my_vector to be a dangling pointer? Or otherwise, does the vector make a deep or a shallow copy of the object pointed to by the pointer returned by my_queue.top()?
No deletions will be made. The only thing being copied/removed/pushed_back are pointers. The objects these point to remain alive, provided they have been dynamically allocated. In that case, you will have to do the clean-up yourself.
Depending on the behaviour desired, you may want to use smart poitners to avoid manual memory management, store SomeClass objects instead of pointers, or leave things as they are and make sure to make a cleanup at the end. Bear in mind that it can be difficult to guarantee that your program will safely get to the point where the memory is released, which is one reason smart pointers are preferred over raw pointers to dynamically allocated objects.
my_queue.pop() will only delete the object stored in the queue; in this case, the pointer itself, not the object pointed by the pointer. So you are fine here.
Mandatory remark: consider using smart pointers instead of raw pointers.
Both the queue and the vector only contain pointers. Unless you use smart pointers or shared pointers neither the destructor of the queue nor that of the vector will free the memory.
No. Since they store pointers, they will copy and destroy pointers (which is a no-op). There's no magic involved. If they never store a pointer to the same object simultaneously you may want to make then store unique_ptrs if you want them to destroy the objects in the end. Alternatively you can store the actual objects in a third vector (vector<SomeClass>), and maintain the vector and queue of pointers separately.
You're storing pointer to SomeClass object everywhere, so no my_queue.pop() just removes the pointer from queue and your object is ok, and you will store a copy of pointer to vector, not a deep copy.
Why do I need to delete dynamically created items in vector, manually? Why wouldn't they get deleted or its destructor called when vector got deleted?
Normally something like this, but why needed ?
vector<int*> v;
for (vector<int*>::iterator it = v.begin(); it != v.end(); ++it)
{
delete *it;
}
Firstly, you store raw pointers in your vector. These pointers are just pointers. They can point anywhere. They can point to local objects, which cannot be deleted by delete. And even if they point to dynamically created objects, it doesn't necessarily mean that the user wants them to die with the vector. How is the vector supposed to know all this?
It is a matter of object ownership. Whoever owns the object is responsible for its proper and timely deletion. Ordinary raw pointers do not express ownership. That is why vector can't make any assumptions about whether the objects need to be deleted or not. If you want to tell the vector that it owns its dynamic objects, use corresponding smart pointers.
Secondly, note that your deletion technique is not necessarily safe in the general case. Some standard containers assume that the data you store in them is always valid. When you do delete on each vector element, the data in the vector becomes "invalidated" (pointers become indeterminate). This is OK with a vector. But doing something like this in a "smarter" container, like std::map or std::unordered_set for example, can and will lead to problems. Even if you destroy the container itself immediately afterwards, it is perfectly possible that the container's destruction algorithm might need to analyze (compare, hash etc.) the values of individual elements. And you just killed them all with your cycle.
Smart pointers naturally resolve this matter. But if you have to use a manual delete for raw pointers stored in a standard container, a better sequence of steps would be this
Retrieve the value of the element at i and store it in pointer p
Erase the element at i from the container
Do delete p
In the end you end up with an empty container and deleted data. Again, your approach will work for simple sequences, like std::vector or std::list, but don't do this with ordered or hashed ones.
Because the language has no way of knowing whether you need them to remain alive when you're done. What if you inserted some pointers to stack objects or something like that? Boom.
This, however, can be remedied by using a smart pointer, which will implement an appropriate policy as to automatic destruction. unique_ptr and shared_ptr are the most common and useful.
The destructor is not called because the pointer does not own the object to which it points.
In C++11, a std::unique_ptr<T> does indeed own the object to which it points. In this case, the destructor is called when the pointer is released, which is probably the behavior you want. (If you don't have a C++11 compiler but have a reasonably recent pre-C++11 compiler, unique_ptr is still available as part of TR1.)
The implementation of vector was just made to delete its memory only. Pointers do not have deconstructors. And in C++, there is no garbage collection or logic to see that it is pointers and recursive delete it.
If you would like to attend the next ISO meeting and propose that, be my guest, but for me, I just put it in an inline function:
template<class T>
public static inline void deleteVectorPointer(std::vector<T*> v)
{
for (vector<T*>::iterator i = v.begin(); i != v.end(); i++)
{
delete *i;
}
}
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.
Say I have this:
Object *myObject;
std::vector<Object> objects(99);
....
myObject = &objects[4];
Would it be safe to assume that myObject's pointer will always be valid no matter how big objects[] gets and if I remove some, as long as I do not ever erase() the actual object pointed to by myObject? Or does it work differently? If the above does not work, how else could I achieve this? It's because in my design, I want a child to have a pointer to its parent, which is assigned by the parent when the child is added, however the parents are in a std::vector, I need random access. Would a std::list be better in my case?
Thanks
No, it is definitely not safe to assume that.
The standard explains what will/won't invalidate iterators on standard containers; any time a vector iterator is invalidated, a pointer into it would be too. In practice this means that when the vector resizes (including implicitly when you call push_back()), any iterators pointing into it will be invalidated, as would your pointer. Similarly, calling erase() will invalidate pointers after the erased item because they all have to move up to fill the erased space.
A std::list would work better; you could maintain in parallel a vector of pointers to the items which would allow you to access them by index without them moving about in memory.
If the vector fills up its allocated space and you try to insert more, it needs to re-allocate its storage, and that will involve copying over the objects and destroying the old storage, which would invalidate the pointer you're keeping around - so no, this is not good enough.
std::list would work fine, since it doesn't rely on continuous storage, but you lose the ability to do quick random access. Alternatively, you can store pointers to your Objects in your collection, in which case you can just take out that element, and the pointer will remain valid until you free that memory in your code - but you will need to handle that yourself at some point.
Another option might be a deque; while deque iterators are invalidated by push_back, direct references to elements (like the pointer you're using here) remain valid.
Provided you keep the vector the same size, you can guarantee this by calling reserve() with the maximum number of elements after declaring it or (as you have done) declaring it with an initial number of elements each constructed to have the default element value.
If you remove or add elements, the underlying storage can get reallocated at any time.
Since you are using raw pointers here, you could use NULL as an "empty element" flag to keep the storage invariant. Since you are setting it up with 99 initially, they will all be NULL after that (the default value for any pointer as a vector element) and reserve is redundant unless you plan to extend the list.
An option that would allow you to not worry about the vector storage would be to store the elements as boost::shared_ptr<Object>. Then any removal of the vector element will only actually delete the referenced Object instance if nobody else is using it.
boost::shared_ptr<Object> myObject;
std::vector<boost::shared_ptr<Object> > objects(99);
myObject = &objects[4];
objects.clear();
// myObject still valid since Object instance referenced thru shared_ptr
Strange, but no one mentioned the boost::stable_vector thing:
...references and iterators to an element of a stable_vector remain valid as long as the element is not erased, and an iterator that has been assigned the return value of end() always remain valid until the destruction of the associated stable_vector.
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.