multi_index_container
具有与复制构造和赋值相关的常用值语义,即,源容器中元素的副本被创建并插入到目标容器中。更有趣的是,复制还会为容器的每个索引重新创建元素排列的原始顺序。这意味着,对于定义了相等性的索引类型,所有索引的相等性在复制或赋值时都得到保留。这种行为可以被视为对复制语义一般规则的自然扩展,该规则声明如果 y
是 x
的副本,则 y==x
。
ctor_args_list
的用法虽然在大多数情况下,multi_index_container
将会被默认构造(或从预先存在的 multi_index_container
复制),但有时有必要为使用的内部对象(键提取器、比较谓词、分配器)指定特定值,例如,如果其中一些对象没有默认构造函数。标准 STL 容器也可能出现相同的情况,它们允许可选地指定此类对象
// example of non-default constructed std::set template<typename IntegralType> struct modulo_less { modulo_less(IntegralType m):modulo(m){} bool operator()(IntegralType x,IntegralType y)const { return (x%modulo)<(y%modulo); } private: IntegralType modulo; }; typedef std::set<unsigned int,modulo_less<unsigned int> > modulo_set; modulo_set m(modulo_less<unsigned int>(10));
multi_index_container
也提供了此功能,尽管方式要复杂得多,因为 multi_index_container
的构造函数必须接受其索引的所有内部对象的值。multi_index_container
构造函数的完整形式是
explicit multi_index_container( const ctor_args_list& args_list=ctor_args_list(), const allocator_type& al=allocator_type());
分配器对象的规范没有特别的问题;至于 ctor_args_list
,此对象被设计为保存 multi_index_container
中每个索引的必要构造值。从用户的角度来看,ctor_args_list
等同于类型
boost::tuple<C0,...,CI-1>
其中 I
是索引的数量,而 Ci
是
nth_index<i>::type::ctor_args
也就是说,第 i
个索引的嵌套类型 ctor_args
。每个 ctor_args
类型本身是一个元组,其中包含关联索引的构造函数参数的值:因此,有序索引需要键提取器对象和比较谓词,哈希索引需要初始桶数、键提取器、哈希函数和相等谓词;而序列索引和随机访问索引不需要任何构造参数。例如,给定定义
typedef multi_index_container< unsigned int, indexed_by< hashed_unique<identity<unsigned int> >, ordered_non_unique<identity<unsigned int>, modulo_less<unsigned int> >, sequenced<>, random_access<> > > modulo_indexed_set;
相应的 ctor_args_list
类型等同于
boost::tuple< // ctr_args of index #0 boost::tuple< std::size_t, // initial number of buckets; 0 if unspecified identity<unsigned int>, boost::hash<unsigned int>, std::equal_to<unsigned int> >, // ctr_args of index #1 boost::tuple< identity<unsigned int>, modulo_less<unsigned int> >, // sequenced indices do not have any construction argument boost::tuple<>, // neither do random access indices boost::tuple<> >
这样的 modulo_indexed_set
不能默认构造,因为 modulo_less
没有提供默认构造函数。下面展示了如何进行构造
modulo_indexed_set::ctor_args_list args_list= boost::make_tuple( // ctor_args for index #0 is default constructible modulo_indexed_set::nth_index<0>::type::ctor_args(), boost::make_tuple(identity<unsigned int>(),modulo_less<unsigned int>(10)), // these are also default constructible (actually, empty tuples) modulo_indexed_set::nth_index<2>::type::ctor_args(), modulo_indexed_set::nth_index<3>::type::ctor_args() ); modulo_indexed_set m(args_list);
示例部分中提供了一个程序,用于实践这些概念。
正如 参考 中详细解释的那样,Boost.MultiIndex 允许使用比 C++ 标准严格要求的更通用的分配器类。支持的一种重要的非标准分配器是由 Boost Interprocess Library 提供的分配器;这为将 multi_index_container
放置在共享内存中提供了可能性。
#include <boost/interprocess/allocators/allocator.hpp> #include <boost/interprocess/managed_shared_memory.hpp> namespace bip=boost::interprocess; // a shared memory compatible allocator of ints typedef bip::allocator< int,bip::managed_shared_memory::segment_manager > shared_int_allocator; // define a shared memory compatible multi_index_container // using shared_int_allocator typedef multi_index_container< int, indexed_by< sequenced<>, ordered_unique<identity<int> > >, shared_int_allocator > unique_int_list; ... // create a managed memory segment bip::managed_shared_memory seg( bip::create_only,"SharedMemoryID",65536); // construct a unique_int_list into the segment unique_int_list* puil=seg.construct<unique_int_list> ("UniqueIntListID") // object identifier within the segment // Construction args: first a ctor arg list, then a // shared memory allocator obtained from the segment object. (unique_int_list::ctor_args_list(), unique_int_list::allocator_type(seg.get_segment_manager()));
示例部分包含一个 程序,进一步探讨了此功能。
可以通过 Boost Serialization Library 存档和检索 multi_index_container
。支持常规和 XML 存档。用法很简单,与任何其他可序列化类型没有什么不同。例如
#include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> #include <fstream> ... void save(const employee_set& es) { std::ofstream ofs("data"); boost::archive::text_oarchive oa(ofs); oa<<es; } void load(employee_set& es) { std::ifstream ifs("data"); boost::archive::text_iarchive ia(ifs); ia>>es; } ... employee_set es; ... // fill it with data save(es); ... employee_set restored_es; load(restored_es);
通过仅链接到适当的 Boost.Serialization 库模块,即可自动提供序列化功能:除了声明过程中使用的存档类型的标头之外,无需显式包含 Boost.Serialization 中的任何标头。但是,如果未使用,则可以通过全局定义宏 BOOST_MULTI_INDEX_DISABLE_SERIALIZATION
来禁用序列化支持。禁用 Boost.MultiIndex 的序列化可以稍微提高构建时间,并且在那些无法正确处理 Boost.Serialization 标头的有缺陷的编译器中可能是必需的。
根据 Boost.MultiIndex 的 值语义,检索存档的 multi_index_container
不仅恢复元素,还恢复它们在容器的每个索引中排列的顺序。但是,此规则有一个例外:对于 哈希索引,不保证元素在恢复的容器中迭代的顺序;通常,依赖哈希索引的元素顺序是不明智的,因为它会在插入或重新哈希期间以任意方式更改——这正是哈希索引和 TR1 无序关联容器未定义相等运算符的原因。
multi_index_container
的索引的迭代器也可以被序列化。迭代器的序列化必须仅在序列化其对应的容器之后进行。
示例 9 在示例部分中展示了 Boost.MultiIndex 的序列化功能。
修订于 2007 年 7 月 17 日
© 版权所有 2003-2007 Joaquín M López Muñoz。根据 Boost 软件许可,版本 1.0 分发。(请参阅随附文件 LICENSE_1_0.txt 或在 https://boost.ac.cn/LICENSE_1_0.txt 复制)