手动提升序列化多图

Posted

技术标签:

【中文标题】手动提升序列化多图【英文标题】:boost serialization multimap manually 【发布时间】:2012-11-17 18:28:18 【问题描述】:

以前我的程序用于在完全填充后序列化整个std::multimap<Participant*, Connection*>。保存和恢复都很简单 arc & _connections

但这需要每个连接对象都留在内存中。但我不需要这些对象来进行序列化以外的任何事情。因此,为了最大限度地减少内存消耗,它决定在创建 std::make_pair(connection->participant(), connection) 后立即对其进行序列化。并在序列化完成后删除。

在填充开始之前,多图的预期大小是已知的。

我想要的是手动序列化这些对,这样我就不需要更改只需 arc & _connections; 的反序列化代码

来自boost/serialization/collections_save_imp.hpp我明白了

boost::serialization::save_construct_data_adl(
    ar, 
    &(*it), 
    boost::serialization::version<BOOST_DEDUCED_TYPENAME Container::value_type>::value
);
ar << boost::serialization::make_nvp("item", *it++);

所以我应该使用类似的东西

typedef std::pair<Participant*, Connection*> PairT;

ar <<  BOOST_SERIALIZATION_NVP(expected_size);

if(3 < ar.get_library_version())// I don't really understand this magic number here
    const unsigned int item_version = boost::serialization::version<PairT>::value;
    ar << BOOST_SERIALIZATION_NVP(item_version);


PairT pair = std::make_pair(connection->participant(), connection);
boost::serialization::save_construct_data_adl(
    ar, 
    pair, 
    boost::serialization::version<PairT>::value
);
ar << boost::serialization::make_nvp("item", pair);
delete connection;

我不确定应该怎么做。只是猜测。

【问题讨论】:

【参考方案1】:

我明白你想要做什么,但我不推荐它,因为它很容易坏掉。 例如,如果您将存档更改为 xml,它将不起作用。如果您升级到更新的 boost 的版本,它也可能会损坏并且可能难以调试。原因是 archive 本身可能会在 start_save() 中添加一些额外的数据(例如类 id),然后它 执行实际的序列化并以调用end_save() 结束。由于这些方法是 受保护,您不能使用它们以可移植/稳定的方式“伪造”序列化。

您可以覆盖(专门化)多图序列化,但这只会让您访问 空容器,您必须使用一些技巧(如全局变量)来访问连接 要序列化的对象:

template<class Archive>
inline void save(Archive& ar, const MultimapT& map, const unsigned version) 
    Connection* p = new Connection( global_data->get(i) );

您还必须反序列化您正在序列化的同一对象,因此唯一干净的方法是为存档提供一个包含处理序列化的多图的对象。该对象可以是拥有地图的类或虚拟对象。但是,这将需要对现有的反序列化代码进行一些更改:

ar << boost::serialization::make_nvp("map",Dummy(&_source));
// and
ar >> boost::serialization::make_nvp("map",Dummy(&_connections));

dummy 的构造函数将获取指向生成连接所需的对象的指针 (保存时)或指向多图的指针(加载时)。然后可以生成假人的save() 方法, 即时存储和删除 Connection 对象,而 load() 方法只是填充多图。

当您动态生成对象时,您必须禁用对象跟踪:

BOOST_CLASS_TRACKING(Connection, boost::serialization::track_never)
BOOST_CLASS_TRACKING(Participant, boost::serialization::track_never)

否则存档会检测到相同的内存地址被重复序列化,并将创建对第一个对象的引用,而不是实际存储数据。

这是一个成员函数示例,用于演示包含多映射(虚拟或父类)的对象的序列化:

// class Foo 

template<typename Archive>
inline void save( Archive& ar, const unsigned version ) const 
    size_t count = expected_count();
    ar << BOOST_SERIALIZATION_NVP(count);
    for( size_t i=0; i<count; ++i ) 
        Connection* connection = make_connection(i);
        PairT pair(connection->participant(), connection);
        ar << boost::serialization::make_nvp("item", pair);
        delete connection;
    


template<typename Archive>
inline void load( Archive& ar, const unsigned version ) 
    size_t count=0;
    ar >> BOOST_SERIALIZATION_NVP(count);
    while( count-- ) 
        PairT pair;
        ar >> boost::serialization::make_nvp("item", pair);
        _connections->insert(pair);
    


friend boost::serialization::access;
BOOST_SERIALIZATION_SPLIT_MEMBER() // split serialize() into save() and load()
// 

参考:intrusive/non-intrusive serialization、splitting save and load、object tracking

【讨论】:

以上是关于手动提升序列化多图的主要内容,如果未能解决你的问题,请参考以下文章

尽管结构已序列化,但提升错误“结构没有名为'序列化'的成员”

提升反序列化优化?

使用模板类提升序列化

以自定义方式提升序列化数据

提升序列化数据的十六进制十进制编码

提升序列化和命名空间