I have a vector populated with objects:
std::vector<Stuff*> stuffVector;
and am trying to delete all开发者_StackOverflow社区 elements of it using a cleanup function
void CleanUp()
{
for (std::vector<Stuff*>::size_type i = 0 ; i < stuffVector.size() ; i++)
{
stuffVector.erase(stuffVector.begin()+i);
}
cout << stuffVector.size() << endl;
if (stuffVector.size() == 0) cout << "Vector Emptied" << endl;
}
This always reports back with a size of however many objects are in the vector, and doesn't actually seem to delete anything at all. It's odd as a similar function works elsewhere to delete a specific object from the vector:
void DestroyStuff()
{
if (stuffVector.size() > 1)
{
for (std::vector<Stuff*>::size_type i = 0 ; i < stuffVector.size() ; i++ )
{
if(stuffVector[i]->CanDestroy())
{
stuffVector.erase (stuffVector.begin()+i);
}
}
}
}
The above works fine, but CleanUp() does not. Why might this be happening?
When you erase an element, the size of the vector changes. So your loops are skipping over elements since on some iterations you erase()
and i++
.
Additionally, to remove every element of a vector
the clear()
function is useful. Also, the standard way of looping through all elements in a vector is to use iterators. Your code should look like this:
void CleanUp()
{
for (std::vector<Stuff*>::iterator it = stuffVector.begin() ; it != stuffVector.end() ; it++)
{
/* .. do something to each element to prepare it for removal */
delete *it; // clean up resources?
}
stuffVector.clear();
cout << stuffVector.size() << endl;
if (stuffVector.size() == 0) cout << "Vector Emptied" << endl;
}
and
void DestroyStuff()
{
for (std::vector<Stuff*>::iterator it = stuffVector.begin() ; it != stuffVector.end() ; /*done inline*/)
{
if((*it)->CanDestroy())
{
it = stuffVector.erase(it);
}
else
++it;
}
}
This loop works because erase()
returns an iterator to the next element in the list.
stuffvector.clear();
(min. length bah!)
This is wrong:
for (std::vector<Stuff*>::size_type i = 0 ; i < stuffVector.size() ; i++)
{
stuffVector.erase(stuffVector.begin()+i);
}
Imagine the vector has elements 0, 1, 2, 3, 4
in it. After the first erase (i==0
), it would be 1, 2, 3, 4
. The second erase with i==1
would render it 1, 3, 4
, and in the end, it will end up as 1, 3
.
The best alternative for clearing a vector would be
stuffVector.clear()
and, if that's unsuitable:
stuffVector.swap(std::vector<Stuff*>());
or
while(!stuffVector.empty()) stuffVector.pop_back();
or
stuffVector.erase(stuffVector.begin(), stuffVector.end());
Other means to delete contents of a vector are left as an exercise for the reader :)
If you wanna do something else with the elements before clearing them (... like deleting the objects the pointers point to) I'd suggest doing that separately and then clearing the vector as separate actions. Or swap with an empty vector and do whatever you want with the swapped vector.
Your problem with CleanUp() is vector::erase() does not call delete to free pointers or object destructors. It just drops the pointers and leaks memory.
Calling erase on an itertaor will invalidate the iterator
stuffVector.erase(stuffVector.begin()+i);
followed by the following in for loop
i++
A pointer, after delete, may not even be read or copied. Destruction invalidates the iterator The following may help
for(it = Entities.begin(); it != Entities.end();)
{
if(...) //Conditional deletion
{
delete * it;
it = Entities.erase(it);
}
else
{
it++;
}
}
精彩评论