修改具有 hashed_non_unique 个键的 Boost Multi-Index Map 中的键范围
Modifying key ranges in a Boost Multi-Index Map having hashed_non_unique keys
我正在尝试更新多索引地图中的一系列元素,但它似乎比我预期的要复杂一些..
给定以下声明:
struct Information {
int number() const {
return number_;
}
int number_;
};
typedef boost::multi_index_container<
Information,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<int>,
boost::multi_index::const_mem_fun<
Information,
int,
&Information::number
>
>
>
> Information_Map;
Information_Map information_map_;
以下是对以上声明内容的总结:
- 一个结构
Information
,其中包含一个任意数字,它不是唯一的
- 具有以下属性的多索引地图
- 包含
Information
类型的元素
- 使用非唯一哈希对元素进行索引
- 散列的键是使用成员函数
Information::number()
构造的
现在,我也声明了这样的东西:
struct Plus_One_Modifier {
void operator()(Information& obj) const {
obj.number_ += 1;
}
};
前面的struct是修饰符,预计在调用modify函数时使用:
// from boost/multi_index/hashed_index.hpp
template<typename Modifier> bool modify(iterator position,Modifier mod);
当此函数仅用于修改一个元素时,一切正常:
// Updates the first element
Information_Map::index<int> index = information_map_.get<int>();
index.modify(index.begin(), Plus_One_Modifier());
问题是,在一种特殊情况下,我必须更新整个容器,像这样:
// Update the whole container the first element
Information_Map::index<int> index = information_map_.get<int>();
for (Information_Map::index<int>::iterator it = index.begin();
it != index.end();
++it) {
index.modify(it, Plus_One_Modifier());
}
前面的代码在大多数情况下无法遍历整个容器,在某些时候迭代器是
以 ++it
等于 end
.
的方式修改
我发现使用第三个变量似乎可以缓解这个问题,但我不相信它是正确的,因为它比容器中的元素进行了更多的迭代..
// Update the whole container the first element
Information_Map::index<int> index = information_map_.get<int>();
Information_Map::index<int>::iterator begin = index.begin();
Information_Map::index<int>::iterator end = index.end();
while (begin != end) {
Information_Map::index<int>::iterator it = begin++;
index.modify(it, Plus_One_Modifier());
}
所以,问题是:
- 我要修改容器中的所有元素
- 修改元素会影响元素在容器中的索引方式,即:修改键
- 修改键会影响元素在容器中的存储方式,这意味着迭代器可能会变得有些混乱
我正在寻找一种安全的方法来更新容器中的一系列元素。
我想到的唯一解决方案如下:
- 列出容器中的所有元素
- 浏览列表并逐一修改元素
这可以正常工作,但性能影响太大
任何帮助将不胜感激
您无法可靠地迭代变异下的散列容器。这不是 Boost Multi Index 特有的:
- Iterator invalidation rules
你可以使用辅助索引来迭代:
auto& aux = information_map_.get<idx_auxiliary>();
auto& idx = information_map_.get<idx_main>();
size_t iterations = 0;
for(auto rait = aux.begin(); rait != aux.end(); ++rait, ++iterations) {
auto it = bmi::project<idx_main>(information_map_, rait);
idx.modify(it, Plus_One_Modifier());
}
// iterations is equal to `information_map_.size()`
当然要确保辅助索引在你在循环中所做的修改下有稳定的迭代器。顺序索引也可能适合此目的。
完整演示
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
struct Information {
Information(int n = 0) : number_(n) {}
int number_;
int number() const { return number_; }
};
static std::ostream& operator<<(std::ostream& os, Information const& i) {
return os << i.number();
}
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<Information,
bmi::indexed_by<
bmi::hashed_non_unique<
bmi::tag<struct idx_main>,
bmi::const_mem_fun<Information, int, &Information::number>
>,
bmi::random_access<bmi::tag<struct idx_auxiliary> >
>
> Information_Map;
struct Plus_One_Modifier {
void operator()(Information& obj) const { obj.number_ += 1; }
};
#include <iostream>
int main() {
Information_Map information_map_;
std::generate_n(std::inserter(information_map_, information_map_.end()), 50, [] { return rand()%20; });
// Updates the first element
auto& aux = information_map_.get<idx_auxiliary>();
auto& idx = information_map_.get<idx_main>();
std::copy(aux.begin(), aux.end(), std::ostream_iterator<Information>(std::cout, " "));
size_t iterations = 0;
for(auto rait = aux.begin(); rait != aux.end(); ++rait, ++iterations) {
auto it = bmi::project<idx_main>(information_map_, rait);
idx.modify(it, Plus_One_Modifier());
}
std::cout << "\nIterations done: " << iterations << "\n";
std::copy(aux.begin(), aux.end(), std::ostream_iterator<Information>(std::cout, " "));
}
输出:
3 6 17 15 13 15 6 12 9 1 2 7 10 19 3 6 0 6 12 16 11 8 7 9 2 10 2 3 7 15 9 2 2 18 9 7 13 16 11 2 9 13 1 19 4 17 18 4 15 10
Iterations done: 50
4 7 18 16 14 16 7 13 10 2 3 8 11 20 4 7 1 7 13 17 12 9 8 10 3 11 3 4 8 16 10 3 3 19 10 8 14 17 12 3 10 14 2 20 5 18 19 5 16 11
我正在尝试更新多索引地图中的一系列元素,但它似乎比我预期的要复杂一些..
给定以下声明:
struct Information {
int number() const {
return number_;
}
int number_;
};
typedef boost::multi_index_container<
Information,
boost::multi_index::indexed_by<
boost::multi_index::hashed_non_unique<
boost::multi_index::tag<int>,
boost::multi_index::const_mem_fun<
Information,
int,
&Information::number
>
>
>
> Information_Map;
Information_Map information_map_;
以下是对以上声明内容的总结:
- 一个结构
Information
,其中包含一个任意数字,它不是唯一的 - 具有以下属性的多索引地图
- 包含
Information
类型的元素
- 包含
- 使用非唯一哈希对元素进行索引
- 散列的键是使用成员函数
Information::number()
构造的
- 散列的键是使用成员函数
现在,我也声明了这样的东西:
struct Plus_One_Modifier {
void operator()(Information& obj) const {
obj.number_ += 1;
}
};
前面的struct是修饰符,预计在调用modify函数时使用:
// from boost/multi_index/hashed_index.hpp
template<typename Modifier> bool modify(iterator position,Modifier mod);
当此函数仅用于修改一个元素时,一切正常:
// Updates the first element
Information_Map::index<int> index = information_map_.get<int>();
index.modify(index.begin(), Plus_One_Modifier());
问题是,在一种特殊情况下,我必须更新整个容器,像这样:
// Update the whole container the first element
Information_Map::index<int> index = information_map_.get<int>();
for (Information_Map::index<int>::iterator it = index.begin();
it != index.end();
++it) {
index.modify(it, Plus_One_Modifier());
}
前面的代码在大多数情况下无法遍历整个容器,在某些时候迭代器是
以 ++it
等于 end
.
我发现使用第三个变量似乎可以缓解这个问题,但我不相信它是正确的,因为它比容器中的元素进行了更多的迭代..
// Update the whole container the first element
Information_Map::index<int> index = information_map_.get<int>();
Information_Map::index<int>::iterator begin = index.begin();
Information_Map::index<int>::iterator end = index.end();
while (begin != end) {
Information_Map::index<int>::iterator it = begin++;
index.modify(it, Plus_One_Modifier());
}
所以,问题是:
- 我要修改容器中的所有元素
- 修改元素会影响元素在容器中的索引方式,即:修改键
- 修改键会影响元素在容器中的存储方式,这意味着迭代器可能会变得有些混乱
我正在寻找一种安全的方法来更新容器中的一系列元素。
我想到的唯一解决方案如下:
- 列出容器中的所有元素
- 浏览列表并逐一修改元素
这可以正常工作,但性能影响太大
任何帮助将不胜感激
您无法可靠地迭代变异下的散列容器。这不是 Boost Multi Index 特有的:
- Iterator invalidation rules
你可以使用辅助索引来迭代:
auto& aux = information_map_.get<idx_auxiliary>();
auto& idx = information_map_.get<idx_main>();
size_t iterations = 0;
for(auto rait = aux.begin(); rait != aux.end(); ++rait, ++iterations) {
auto it = bmi::project<idx_main>(information_map_, rait);
idx.modify(it, Plus_One_Modifier());
}
// iterations is equal to `information_map_.size()`
当然要确保辅助索引在你在循环中所做的修改下有稳定的迭代器。顺序索引也可能适合此目的。
完整演示
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
struct Information {
Information(int n = 0) : number_(n) {}
int number_;
int number() const { return number_; }
};
static std::ostream& operator<<(std::ostream& os, Information const& i) {
return os << i.number();
}
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<Information,
bmi::indexed_by<
bmi::hashed_non_unique<
bmi::tag<struct idx_main>,
bmi::const_mem_fun<Information, int, &Information::number>
>,
bmi::random_access<bmi::tag<struct idx_auxiliary> >
>
> Information_Map;
struct Plus_One_Modifier {
void operator()(Information& obj) const { obj.number_ += 1; }
};
#include <iostream>
int main() {
Information_Map information_map_;
std::generate_n(std::inserter(information_map_, information_map_.end()), 50, [] { return rand()%20; });
// Updates the first element
auto& aux = information_map_.get<idx_auxiliary>();
auto& idx = information_map_.get<idx_main>();
std::copy(aux.begin(), aux.end(), std::ostream_iterator<Information>(std::cout, " "));
size_t iterations = 0;
for(auto rait = aux.begin(); rait != aux.end(); ++rait, ++iterations) {
auto it = bmi::project<idx_main>(information_map_, rait);
idx.modify(it, Plus_One_Modifier());
}
std::cout << "\nIterations done: " << iterations << "\n";
std::copy(aux.begin(), aux.end(), std::ostream_iterator<Information>(std::cout, " "));
}
输出:
3 6 17 15 13 15 6 12 9 1 2 7 10 19 3 6 0 6 12 16 11 8 7 9 2 10 2 3 7 15 9 2 2 18 9 7 13 16 11 2 9 13 1 19 4 17 18 4 15 10
Iterations done: 50
4 7 18 16 14 16 7 13 10 2 3 8 11 20 4 7 1 7 13 17 12 9 8 10 3 11 3 4 8 16 10 3 3 19 10 8 14 17 12 3 10 14 2 20 5 18 19 5 16 11