proc_prune: avoid using invalidated iterator

An `std::vector<T>::reverse_iterator` stores the
`std::vector<T>::iterator` which points to the (forwards-ordered)
*following* item.  Thus while `vec.rbegin()` dereferences to the final
item of `vec`, the iterator it wraps (`vec.rbegin().base()`) is equal to
`vec.end()`.

In the remove case here, we advance `it` (backwards), erasing the item
we just advanced past by grabbing its (pre-increment) base
forward-iterator and subtracting 1.

The iterator maths here is obviously all OK, but the forward-iterator
that `it` wraps post-increment actually points to the item we just
removed.  That iterator was invalidated by the `erase()` call.

That this works anyway is (AFAICT) some combination of luck and/or
promises that aren't part of the C++ spec, but MSVC's debug iterator
support picks this up.

`erase()` returns the new iterator that follows the item just erased,
which happens to be the exact one we want our reverse-iterator to wrap
for the next loop; we get a fresh iterator to the same base, now without
the preceding item.
This commit is contained in:
Charlotte 2023-06-21 19:05:02 +10:00 committed by Charlotte Connor
parent 104edb4587
commit 63e4114233
1 changed files with 1 additions and 1 deletions

View File

@ -91,7 +91,7 @@ struct PruneWorker
if (GetSize(new_lhs) == 0) {
if (GetSize(conn_lhs) == 0)
removed_count++;
cs->actions.erase((it++).base() - 1);
it = decltype(cs->actions)::reverse_iterator(cs->actions.erase(it.base() - 1));
} else {
it->first = new_lhs;
it->second = new_rhs;