3

In C++, how can I delete an element from a vector?

  1. Delete it right from where it is, i.e. let the vector resize
  2. Swap the element to be deleted with the last element s.t. pop_back() can be used (which I hope doesn't involve copying everything around...)

For (1), I've tried the following, but I'm not quite sure if it does what it is supposed to do (remove the item passed to removeItem() ), and it doesn't seem very elegant:

vector<Item*> items; // fill vector with lots of pointers to item objects (...) void removeItem(Item * item) { // release item from memory if (int i = getItemIdIfExists(item) != -1) { items.erase (items.begin()+i); } } int getItemIdIfExists(Item * item) { // Get id of passed-in Item in collection for (unsigned int i=0; i<items.size(); i++) { // if match found if (items[i] == item) return i; } // if no match found return -1; } 
0

3 Answers 3

8

The standard remove+erase idiom removes elements by value:

#include <vector> #include <algorithm> std::vector<int> v; v.erase(std::remove(v.begin(), v.end(), 12), v.end()); 

remove reorders the elements so that all the erasees are at the end and returns an iterator to the beginning of the erasee range, and erase actually removes the elements from the container.

This is as efficient as you can get with a contiguous-storage container like vector, especially if you have multiple elements of the same value that all get erased in one wash.

Sign up to request clarification or add additional context in comments.

1 Comment

Shouldn't that just be remove instead of v.remove?
2
void removeItem(Item*item){ for(int i=0; i<items.size(); i++){ if (items[i]==item){ swap(items[i], items.back()); items.pop_back(); return; } } } 

Though, if the order doesn't matter, why not just use a std::set?

3 Comments

Thank you, that solves my problem. It also only deletes one element (which is what I want). My own code seemed to delete multiple elements for some reason. Regarding the set, I am not quite sure why I would use it!? Apart from this particular case, my access is mainly sequential (i.e. all items are updates, all items are rendered etc).
I wasn't sure how you were using it so I was thinking that removing items from a set would be faster than from a vector (even if we're not shifting the whole vector, it's still O(n) for my removeItem), but if you don't do too many removes, you should be fine with the vector.
Well, the items are collectables in a game, so they are updated and rendered sequentially every frame, whereas they are only removed every so often when the player actually collects them. So I guess the vector is the better choice in this case.
1

Delete it right from where it is, i.e. let the vector resize

That's what erase does.

Swap the element to be deleted with the last element s.t. pop_back() can be used (which I hope doesn't involve copying everything around...)

That's what remove does, except that it preserves the order of the remaining objects so it does involve copying everything around.

What you've done could be written as:

items.erase( std::remove( items.begin(), items.end() , item ) , items.end() ); 

The difference with your code being that this will actually remove all items valued item, instead of just the first one.

2 Comments

With your code I get the following error: cannot convert '__gnu_cxx::__normal_iterator<Item**, std::vector<Item*, std::allocator<Item*> > >' to 'const char*' for argument '1' to 'int remove(const char*)'|
That's not quite what remove does. It involves copying because it preserves the order of the remaining items.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.