-1

Hi I am a beginner in c++ and I would like to know why this code returns a Debug Assertion Failed error everytime an object is erased from the list.

for (auto it = ProjectileList.end(); it != ProjectileList.begin();) {
            --it;
            if (it->position_y < 0) {
                ProjectileList.erase(it);
            }
            else {
                it->Draw(window.renderer);
                it->position_y--;
            }
        }
Froncis
  • 21
  • 1
  • What is `ProjectionList`? A `std::list`? A `std::vector`? – ph3rin Jun 11 '21 at 00:26
  • 1
    When iterating backwards, you should consider using **reverse iterators** instead. The trick in this case is that `erase()` takes and returns an `iterator` not a `reverse_iterator`, but that is [not hard to work around](https://stackoverflow.com/questions/37005449/), eg: `for (auto it = ProjectileList.rbegin(); it != ProjectileList.rend(); ) { if (it->position_y < 0) { it = decltype(it){ProjectileList.erase(std::next(it).base())}; } else { it->Draw(window.renderer); it->position_y--; ++it; } }` – Remy Lebeau Jun 11 '21 at 01:16

2 Answers2

3

You have to assign the new iterator that the function erase() returns to it.

for (auto it = ProjectileList.end(); it != ProjectileList.begin();) {
    --it;
    if (it->position_y < 0) {
        it = ProjectileList.erase(it); // assign the new iterator
    }
    else {
        it->Draw(window.renderer);
        it->position_y--;
    }
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
2

Another solution would have been to write two loops, one that erases, and the other that draws. Using the std::remove_if could be used:

#include <algorithm>
//...
// Erase 
auto iter = std::remove_if(ProjectileList.begin(), ProjectileList.end(), 
                          [&] (auto& p) { return p.position_y < 0; });
ProjectileList.erase(iter, ProjectileList.end());

// Now draw the remaining ones. 
for (auto& p : ProjectileList)
{
    p.Draw(window.renderer);
    p.position_y--;
}
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • You should probably preserve the original code's backwards iteration while drawing. You can't do that with a `range-for` loop (without using an adapter for that purpose), but you can use reverse iterators instead, eg: `for (auto it = ProjectileList.rbegin(); it != ProjectileList.rend(); ++it) { it->Draw(window.renderer); it->position_y--; }` – Remy Lebeau Jun 11 '21 at 01:04