- Iterators are never invalidated as long as the element is not erased. Please note that invalidation is not the same as repositioning (caused by re-ordering).
- Iterators to an index dependent on key A will not be invalidated nor repositioned (i.e., the index keeps its order) upon changes on a different key B, as long as the affected element is not erased (which can happen if the index dependent on key B is unique).
- If you want to safely range over an A-index modifying B keys even in the case of erasures, you can do as exemplified below:
Live On Wandbox
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/key.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
#include <iterator>
using namespace boost::multi_index;
struct element
{
int a;
int b;
};
using container=multi_index_container<
element,
indexed_by<
ordered_unique<key<&element::a>>,
ordered_unique<key<&element::b>>
>
>;
int main()
{
container c={{0,0},{1,1},{2,2},{3,3},{4,4},{5,5}};
auto print=[](auto& c){
for(const auto& x:c)std::cout<<"{"<<x.a<<","<<x.b<<"}";
std::cout<<"\n";
};
std::cout<<"before: ";
print(c);
for(auto first=c.begin(),last=c.end();first!=last;){
// we get next position now in case first will be invalidated
auto next=std::next(first);
c.modify(first,[](auto& x){
x.b*=2;
});
first=next;
}
std::cout<<"after: ";
print(c);
}
Output
before: {0,0}{1,1}{2,2}{3,3}{4,4}{5,5}
after: {0,0}{3,6}{4,8}{5,10}
Expanded answer: When you're modifying the key of the index you're ranging on, you can either do a first pass to store all the iterators in the range before doing any actual modification (see modify_unstable_range
here) or, in case you want to do the thing in just one pass, store the addresses of modified elements along the way to avoid revisitation:
Live On Wandbox
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/key.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
#include <iterator>
#include <unordered_set>
using namespace boost::multi_index;
struct element
{
int a;
int b;
};
using container=multi_index_container<
element,
indexed_by<
ordered_unique<key<&element::a>>,
ordered_unique<key<&element::b>>
>
>;
int main()
{
container c={{0,0},{1,1},{2,2},{3,3},{4,4},{5,5}};
auto print=[](auto& c){
for(const auto& x:c)std::cout<<"{"<<x.a<<","<<x.b<<"}";
std::cout<<"\n";
};
std::cout<<"before: ";
print(c);
std::unordered_set<const element*> visited;
for(auto first=c.begin(),last=c.end();first!=last;){
// we get next position now before first is invalidated/repositioned
auto next=std::next(first);
if(c.modify(first,[](auto& x){
x.a*=2; // note we're modifying the key of the index we're at
})){
// element succesfully modified, store address to avoid revisitation
visited.insert(&*first);
}
// move to next nonvisited element
first=next;
while(first!=last&&visited.find(&*first)!=visited.end())++first;
}
std::cout<<"after: ";
print(c);
}
Output
before: {0,0}{1,1}{2,2}{3,3}{4,4}{5,5}
after: {0,0}{6,3}{8,4}{10,5}