【发布时间】:2020-03-28 11:24:12
【问题描述】:
在测试中它似乎工作正常,但我在文档中找不到任何关于预期行为的提及。
基本上,如果我的 multi_index_container 分别使用键 A 和 B 有 2 个 ordered_non_unique 索引,如果我从 A 迭代一个范围并修改 B 值(这可能导致重新排序),A 的迭代器是否无效?
【问题讨论】:
标签: c++ loops iterator containers boost-multi-index
在测试中它似乎工作正常,但我在文档中找不到任何关于预期行为的提及。
基本上,如果我的 multi_index_container 分别使用键 A 和 B 有 2 个 ordered_non_unique 索引,如果我从 A 迭代一个范围并修改 B 值(这可能导致重新排序),A 的迭代器是否无效?
【问题讨论】:
标签: c++ loops iterator containers boost-multi-index
#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);
}
输出
before: {0,0}{1,1}{2,2}{3,3}{4,4}{5,5}
after: {0,0}{3,6}{4,8}{5,10}
扩展答案:当您修改您要测距的索引的键时,您可以在进行任何实际修改之前先执行一次以将所有迭代器存储在该范围内(请参阅modify_unstable_rangehere) 或者,如果您只想一次性完成此操作,请在此过程中存储修改元素的地址以避免重新访问:
#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);
}
输出
before: {0,0}{1,1}{2,2}{3,3}{4,4}{5,5}
after: {0,0}{6,3}{8,4}{10,5}
【讨论】: