0

I have an std::vector<Bullet> bullets and in the for-loop below I want to remove a bullet from the vector if it's not alive anymore.

My plan is to remove the element with pop_back(). If there are more than one element in the vector I want to first swap the element that is to be removed with the last element in the vector, and then call pop_back().

for (std::vector<Bullet>::iterator b = bullets.begin(); b != bullets.end(); ++b) { if(!b->isAlive()) { if (bullets.size() > 1) { std::iter_swap(bullets + ..., bullets.end()); } bullets.pop_back(); } } 

The problem is the first parameter in iter_swap. I looked up http://www.cplusplus.com/reference/algorithm/iter_swap/ and the syntax for the first parameter is the vector + the position of the element.

How do I find out b's index in the vector?

7
  • 1
    Either I'm missing something, or you need an iterator for the first element and already have the right iterator: b. Commented Jul 10, 2014 at 17:48
  • 2
    @Cyber Because that takes linear time while swap-and-pop takes constant time. Commented Jul 10, 2014 at 17:48
  • 1
    For the record, b - bullets.begin() would give the index. Commented Jul 10, 2014 at 17:52
  • 2
    @delnan Your for loop takes linear time. Remove-erase is swap-and-pop. Commented Jul 10, 2014 at 17:52
  • 3
    Don't you want iter_swap(b, bullets.end() - 1) (emphasis on "- 1")? Commented Jul 10, 2014 at 18:02

2 Answers 2

3

If the condition governing whether an element is to be removed or not is :

object->isAlive() 

Then you should use an STL way to do the removal, namely the erase-remove idiom :

bullets.erase(std::remove_if(bullets.begin(), bullets.end(), [](Bullet const& b) { return !b.isAlive(); }), bullets.end()); 

Now, to answer your particular question an iterator's it index in a vector v can be obtained like so :

auto indx = std::distance(v.begin(), it); 
Sign up to request clarification or add additional context in comments.

Comments

3

There's an easier way to filter a std::vector.

#include <algorithm> auto part = std::remove_if( bullets_.begin(), bullets_.end(), [](const Bullet &bullet) { return !bullet.isAlive(); }); bullets_.erase(part, bullets_.end()); 

This will partition the vector into the alive and dead bullets, and then you delete the segment with the dead bullets.

The std::remove_if() function is like partition() but only the order of the first partition is preserved.

4 Comments

Thanks. What type is that auto there? My doesn't support it.
@A.D. Time to upgrade your compiler... or at least turn on modern C++ support. That's C++11.
Yes, I know. I was wondering what the type is so I can exchange the auto for it and then use your solution.
@A.D. If you don't support auto you'll probably need to replace the lambda with a functor object as well. You can replace auto with the iterator type for your vector.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.