Reputation: 257
I have a boost::multi_index
with a hashed_non_unique
view. What I would like to accomplish is, given a key in that view, use
pair<myIter, myIter> iterRange = myView.equal_range(key);
for (myIter iter = iterRange.first; iter != iterRange.second; ++iter) {
// ...
}
to find all elements associated with that key. Then, run these elements through a filter
bool filter(Element e) { /* some filtering logic*/ }
and modify the filtered results with a modifier
void modifier(Element e) { /* modify the elements with e.g. myView.modify() */ }
However, simply putting these pieces together doesn't work since modifying the elements results in reordering of the multi_index, which renders my iterRange invalid.
What would be the correct way to do this? Thanks!
Upvotes: 1
Views: 657
Reputation: 5658
Some comments to your proposed solution:
BMIter
is not special as you seem to imply, but merely the iterator associated to the first index of the container. Note that this will be the same as myIter
when myView
happens to be this first index.iters
as a vector<myIter>
and store the iterators directly without any further conversion --you're still achieving the intended effect of not being affected by potential reorderings after modification.iterRange.second
). With this mind, you can spare the iters
trick as follows:
for (myIter iter = iterRange.first; iter != iterRange.second; ) {
auto nextIter = std::next(iter);
if (filter(*iter)) {
myView.modify(iter, modifier);
if (nextIter != iterRange.second && std::next(iter) == iterRange.second)
iterRange.second = iter;
}
iter = nextIter;
}
Upvotes: 2
Reputation: 257
I think I've found the answer myself. Instead of simply modifying the elements inside the for loop, we need to cache the elements first and modify them later to avoid altering the ordering. The trick here is, instead of caching the iterators to this specific view, cache instead iterators to the elements themselves, i.e.
vector<BMIIter> iters;
for (myIter iter = iterRange.first; iter != iterRange.second; ++iter) {
if (filter(*iter)) {
iters.push_back(myBMI.iterator_to(*iter));
}
}
for (auto iter : iters) {
myBMI.modify(iter, modifier);
}
Note that BMIIter
and myIter
are different iterator types - the former is an iterator to the element itself, while the latter is iterator specific to myView. Modifying elements in the multi_index invalidates the latter, but the former still holds valid even after reordering happened.
Upvotes: 0