我可以依赖在内存映射文件中分配的 boost multi_index_container 吗?这种“数据库”可以在具有相同字节序的计算机之间移植吗?
3 回答
不,这不安全。内存映射文件中第一个字节的地址不能保证在调用之间是相同的。
Boost 的内存映射文件需要一个hint
,但这只是一个提示。
所以在第一次调用中,内存可能位于0xBAADF00D
. 在第二次调用时,它可能位于0xF00DBAAD
. 结构中的指针将不再有效,因为它们将指向内存 around0xBAADF00D
而不是 around 0xF00DBAAD
。
作为一个严重的问题,它通常可能在测试中起作用,因为hint
通常可能会遵守 - 但有时该内存地址已经存在东西,并且hint
必须忽略。
(还有其他部分让这变得非常困难——但上面的内容让它变得非常不可行)。
现在,像这样的策略可以工作,但需要对所讨论的数据结构进行非常侵入性的内省。为了使数据结构具有正确的偏移量,您必须执行 DLL 重新寻址之类的过程,到那时您还不如将其序列化为平面。
借助Boost.Interprocess 的内存映射文件并稍加注意,您可以将其持久化multi_index_container
;映射位于不同地址的问题可以使用偏移量而不是指针来解决,而 Boost.MultiIndex 已准备好处理该问题:请参阅此示例,其中实现了一种简单的数据库,一次访问多个进程。
这就是说,使用内存映射文件进行持久化是一种非常脆弱的方法,因为它只有在这些参数完全相同的情况下才有效:
- 机器架构
- 操作系统版本
- 编译器版本
- 编译参数(例如,可能会影响填充)
- 使用的所有相关库的版本(包括 Boost),因为 ABI 可能会因版本而异
- 我忘记了其他一些方面:-)
考虑到一切,使用@alfC 建议的Boost.Serialization 可能是跨不同环境的可移植持久性的最佳解决方案。如果您担心速度,像这样的混合方法可能会起作用:
- 当在同一台机器上使用相同结构的多个进程(理想情况下,在同一个可执行文件之外)的会话和上下文中,内存映射容器。
- 一旦会话完成(或每隔一段时间以防止崩溃等),使用 Boost.Serialization 可移植地保持。
如果您想要将multi_index
一个计算机从一台计算机传输到另一台计算机,最好的办法是使用 Boost.Serialization,它开箱即用:
http://www.boost.org/doc/libs/1_60_0/libs/multi_index/doc/tutorial/creation.html#serialization
#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; // a multi_index type
... // fill it with data
save(es);
...
employee_set restored_es;
load(restored_es);