【问题标题】:How to serialize boost::dynamic_bitset?如何序列化 boost::dynamic_bitset?
【发布时间】:2015-09-09 11:44:07
【问题描述】:

如何用 boost::dynamic_bitset 成员序列化一个类?

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/serialization/bitset.hpp>
#include <sstream>

class A
{
    friend class boost::serialization::access;
    boost::dynamic_bitset<> x;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int){
        ar & x;
    }
};

int main()
{
    A a;
    std::stringstream ss;
    boost::archive::text_oarchive oa(ss);
    oa << a;
    return 0;
}

编译出错(提升 1.57)

In file included from /usr/include/boost/serialization/extended_type_info_typeid.hpp:37:0,
                 from /usr/include/boost/archive/detail/oserializer.hpp:38,
                 from /usr/include/boost/archive/detail/interface_oarchive.hpp:23,
                 from /usr/include/boost/archive/detail/common_oarchive.hpp:22,
                 from /usr/include/boost/archive/basic_text_oarchive.hpp:32,
                 from /usr/include/boost/archive/text_oarchive.hpp:31,
                 from dynamic_bitset_setial.cpp:1:
/usr/include/boost/serialization/access.hpp: In static member function ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::text_oarchive, T = boost::dynamic_bitset<>]’:
/usr/include/boost/serialization/serialization.hpp:69:5:   instantiated from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::text_oarchive, T = boost::dynamic_bitset<>]’
/usr/include/boost/serialization/serialization.hpp:128:9:   instantiated from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::text_oarchive, T = boost::dynamic_bitset<>]’
/usr/include/boost/archive/detail/oserializer.hpp:148:5:   instantiated from ‘void boost::archive::detail::oserializer<Archive, T>::save_object_data(boost::archive::detail::basic_oarchive&, const void*) const [with Archive = boost::archive::text_oarchive, T = boost::dynamic_bitset<>]’
dynamic_bitset_setial.cpp:25:1:   instantiated from here
/usr/include/boost/serialization/access.hpp:118:9: error: ‘class boost::dynamic_bitset<>’ has no member named ‘serialize’

【问题讨论】:

    标签: c++ boost boost-dynamic-bitset


    【解决方案1】:

    我继续 filed the pull request 为 Boost Dynamic Bitset 添加序列化支持

    使用公共接口的序列化不是最佳的,因为to_block_range()/from_block_range() 需要复制m_bits(以及后续的resize())。

    我向 Boost Dynamic Bitset 添加了一个通用实现。更改干净地合并到开发或主 (1_58_0)。

    变化

    添加的实现
    • 最小的干扰,只有一个嵌套的朋友 (class serialization_impl;) 已被转发声明以“锁孔”所需的朋友访问权限
    • 此类以及用于 Boost 序列化的实际 ADL 挂钩在单独的标头中实现(dynamic_bitset/serialization.hpp,类似于其他支持序列化的 boost 库)。
    • 这意味着存在对 Boost 序列化内容的零依赖,除非实际包含 boost/dynamic_bitset/serialization.hpp
    • 实现了零拷贝(利用 std::vector&lt;Block&gt; 在 Boost 序列化中的内置支持)

    测试

    拉取请求中的第二次提交添加了对此功能的测试。我不确定如何将dyn_bitset_unit_tests5.cpp 添加到 Jamfile。我想必须做其他事情来确保链接到 Boost System 和 Boost Serialization。我已经使用一个简单的包装器自己运行了测试:

    #include <modular-boost/libs/dynamic_bitset/dyn_bitset_unit_tests5.cpp>
    
    int main() {
        test_main(0, nullptr);
    }
    

    然后可以使用例如编译和运行

    g++ main.cpp -lboost_system -lboost_serialization && ./a.out
    

    没有输出意味着没有错误。

    【讨论】:

    • 使用这种序列化实现没有动态位集爆炸的风险吗?
    • 嗯。为什么。我还没有看到类爆炸。并且实现不是太复杂。我觉得很好听是什么让你问这个,@MMA?
    • 如果动态位集占用 10GB 内存,那么序列化对象也将是 10GB?
    • 大概是的(假设是二进制档案)。在这种情况下,您想要使用补丁版本(请参阅拉取请求),因为它启用了零拷贝。
    【解决方案2】:

    dynamic_bitset&lt;&gt; 不可序列化,正如您所发现的(std::bitset&lt;N&gt; 是不同的类型)。

    不过不用担心,您可以毫不费力地添加它:

    namespace boost { namespace serialization {
    
        template <typename Ar, typename Block, typename Alloc>
            void save(Ar& ar, dynamic_bitset<Block, Alloc> const& bs, unsigned) {
                size_t num_bits = bs.size();
                std::vector<Block> blocks(bs.num_blocks());
                to_block_range(bs, blocks.begin());
    
                ar & num_bits & blocks;
            }
    
        template <typename Ar, typename Block, typename Alloc>
            void load(Ar& ar, dynamic_bitset<Block, Alloc>& bs, unsigned) {
                size_t num_bits;
                std::vector<Block> blocks;
                ar & num_bits & blocks;
    
                bs.resize(num_bits);
                from_block_range(blocks.begin(), blocks.end(), bs);
                bs.resize(num_bits);
            }
    
        template <typename Ar, typename Block, typename Alloc>
            void serialize(Ar& ar, dynamic_bitset<Block, Alloc>& bs, unsigned version) {
                split_free(ar, bs, version);
            }
    
    } }
    

    这有效,例如Live On Coliru

    int main() {
        A a;
        for (int i=0; i<128; ++i)
            a.x.resize(11*i, i%2);
    
        std::stringstream ss;
        {
            boost::archive::text_oarchive oa(ss);
            oa << a;
        }
        std::cout << ss.str();
        {
            boost::archive::text_iarchive ia(ss);
            A b;
            ia >> b;
    
            assert(a.x == b.x);
        }
    }
    

    请注意,如果您无法复制块向量,则直接在m_bits 级别上添加序列化同样容易,但这需要进行侵入性更改(至少需要好友访问权限)。

    这样的东西很容易被添加到拉取请求中。

    更新added that pull request

    【讨论】:

    • 我已经添加了我描述的拉取请求。我认为它足够干净和有用
    • 使用您的代码序列化 dynamic_bitset,我正在序列化为 text_iarchive,文件的内容令我感到惊讶。我创建了一个长度为 454 的位集,并用随机值(0 或 1)填充它。当我查看文件的内容时,我看到:22 serialization::archive 12 0 0 454 8 0 13498754571592366336 199811248968146936 0 8917879989572726124 17597677761915498957 13906573370107724280 1703115579025708 5578 2950082248053176559 63。我不应该期望看到位列表吗?
    • 是的,你不应该期待。序列化是为了传输。我认为 OP 无论如何都是在(有效的)二进制序列化之后,请参阅其他答案以获得最佳效果。如果您想要这些位,只需这样写:Live On Coliru。或者,您知道,只需使用operator&lt;&lt; 写信给std::cout,因为您以可读的方式呈现,而不仅仅是电汇编码。
    • @DavidDoria ^ 我忘了把你链接到那个
    • 它工作得很好,所以我想是这样的——我想我只是好奇这些数字是如何代表一个位集的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    • 2018-02-05
    相关资源
    最近更新 更多