c++ - 将 boost 序列化集成到现有代码中

标签 c++ serialization boost

我有以下形式的代码:

ODIstream &operator<<(ODIstream& vis, const Song &lyrics)
{
  vis >> doh;
  vis >> a;
  vis >> deer;
  vis >> a;
  vis >> female;
  vis >> deer;  
}

其中 ODIStream 是旧的已弃用类库的序列化函数,female 是来自已弃用类库的容器。它们一起工作,因为它们是为彼此构建的。我的任务是更新此代码并删除此库,因此我们可以:

istream &operator<<(istream& vis, const Song &lyrics)
{
  vis >> doh;
  vis >> a;
  vis >> deer;
  vis >> a;
  vis >> female;
  vis >> deer;  
}

但 female 不适用于 ostream。当我将 female 更改为没有内置序列化运算符的 STL::list 时(单个类元素有)。

我打算使用 boost:serialisation code但我不确定如何将存档与当前代码模型集成。

有人做过吗?

最佳答案

请注意,序列化的目标与流式传输不同。

序列化生成一个存档。因此,您不会写入 ostream,也不会从 istream 读取。相反,您将写入 oarchive(文本、二进制、xml)或从相应的 iarchive 中读取。

每个存档都将携带(相当多的)存档 header 。因此,将存档作为流操作符内部的一个细节来考虑似乎不是一个好主意,快速演示:

#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/serialization.hpp>

struct Simplest    {
    int i;    

    template <typename Archive> void serialize(Archive& ar, unsigned /*version*/) {
        ar & i;
    }

    friend std::ostream& operator<<(std::ostream& os, Simplest const& data) {
        boost::archive::text_oarchive oa(os);
        oa << data;
        return os;
    }
};

int main() {
    Simplest a { 4215680 }, b { -42 };
    std::cout << a << b;
}

这会导致

22 serialization::archive 10 0 0 4215680
22 serialization::archive 10 0 0 -42

所有只是为了序列化... 2 个整数。

此外,Boost Serialization 旨在处理存档错误。但是,如果读取(“解析”)失败,通常期望输入流操作符离开输入位置,并且必须注意将流状态保持在适当的状态,以便仍然可以使用流。

我建议采用以下两种方法之一:

1。一路使用Boost序列化

想象一个示范性的结构

struct Demo
{
    int i;
    std::string truth;

    using Vars = std::map<std::string, double>;
    Vars vars;
};

使用简单的序列化实现和(以及一个仅用于调试打印的助手):

int main()
{
    Demo a { 42, "LtUaE", { { "PI", 3.1415926 }, { "e", std::exp(1.0) } } };
    std::cout << "Debug : " << a << "\n";

    std::string const serialized = serialize(a);
    std::cout << "Serious serialization: " << serialized << "\n";

    // to parse back:
    Demo roundtrip = deserialize(serialized);
    std::cout << "Parsed back: " << roundtrip << "\n";
}

我们得到

Debug : 42;LtUaE;PI;3.14159;e;2.71828;
Serious serialization: 22 serialization::archive 10 0 0 42 5 LtUaE 0 0 2 0 0 0 2 PI 3.1415926000000001 1 e 2.7182818284590451
Parsed back: 42;LtUaE;PI;3.14159;e;2.71828;

查看 Live On Coliru

这里的一大优势是很容易获得二进制流:Live On Coliru too :

#include <map>
#include <sstream>
#include <iomanip>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/map.hpp>

struct Demo
{
    int i;
    std::string truth;

    using Vars = std::map<std::string, double>;
    Vars vars;

    template <typename Archive> void serialize(Archive& ar, unsigned /*version*/)
    {
        ar & i;
        ar & truth;
        ar & vars;
    }

    friend std::ostream& operator<<(std::ostream& os, Demo const& demo)
    {
        os << demo.i << ';' << demo.truth << ";";
        for (auto& e : demo.vars)
            os << e.first << ";" << e.second << ";";
        return os;
    }
};

static std::string as_hex(std::string const& binary)
{
    std::ostringstream oss;
    for (unsigned ch: binary)
        oss << std::setw(2) << std::setfill('0') << std::hex << ch;

    return oss.str();
}

static std::string serialize(Demo const& data)
{
    std::ostringstream oss;
    boost::archive::binary_oarchive oa(oss);
    oa << data;

    return oss.str();
}

static Demo deserialize(std::string const& text)
{
    std::istringstream iss(text);
    boost::archive::binary_iarchive ia(iss);
    Demo data;
    ia >> data;
    return data;
}

int main()
{
    Demo a { 42, "LtUaE", { { "PI", 3.1415926 }, { "e", std::exp(1.0) } } };
    std::cout << "Debug : " << a << "\n";

    std::string const serialized = serialize(a);
    std::cout << "Serious serialization: " << as_hex(serialized) << "\n";

    // to parse back:
    Demo roundtrip = deserialize(serialized);
    std::cout << "Parsed back: " << roundtrip << "\n";
}

2。使用 boost spirit

使用相同的 Demo 结构和

int main()
{
    Demo a { 42, "LtUaE", { { "PI", 3.1415926 }, { "e", std::exp(1.0) } } };
    std::cout << "Quick serialization: " << karma::format_delimited(karma::auto_, ';', a) << "\n";

    std::string const serialized = serialize(a);
    std::cout << "Serious serialization: " << serialized << "\n";

    // to parse back:
    Demo roundtrip = deserialize(serialized);
    std::cout << "Parsed back: " << karma::format_delimited(karma::auto_, ';', roundtrip) << "\n";
}

打印:

Quick serialization: 42;LtUaE;PI;3.142;e;2.718;
Serious serialization: Demo{42;LtUaE;{{PI: 3.142}, {e: 2.718}}}
Parsed back: 42;LtUaE;PI;3.142;e;2.718;

查看 Live On Coliru

#include <map>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>

namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;

struct Demo
{
    int i;
    std::string truth;

    using Vars = std::map<std::string, double>;
    Vars vars;
};

BOOST_FUSION_ADAPT_STRUCT(Demo, (int,i)(std::string,truth)(Demo::Vars, vars))

static std::string serialize(Demo const& data)
{
    std::ostringstream oss;
    oss << karma::format(
            "Demo{" << karma::int_ << ';' << karma::string << ';' 
                << '{' 
                        << ('{' << karma::string << ": " << karma::double_ << '}') % ", " 
                << '}'
            << '}', data);

    return oss.str();
}

static Demo deserialize(std::string const& text)
{
    auto f(text.begin()), l(text.end());
    Demo parsed;
    if (qi::parse(f, l,
            "Demo{" >> qi::int_ >> ';' >> +~qi::char_(';') >> ';' 
            >> '{' 
                >> ('{' >> +~qi::char_(':') >> ": " >> qi::double_ >> '}') % ", " >> '}'
            >> '}', parsed))
    {
        return parsed;
    }
    throw std::runtime_error("Parse failed at '" + std::string(f,l) + "'");
}

int main()
{
    Demo a { 42, "LtUaE", { { "PI", 3.1415926 }, { "e", std::exp(1.0) } } };
    std::cout << "Quick serialization: " << karma::format_delimited(karma::auto_, ';', a) << "\n";

    std::string const serialized = serialize(a);
    std::cout << "Serious serialization: " << serialized << "\n";

    // to parse back:
    Demo roundtrip = deserialize(serialized);
    std::cout << "Parsed back: " << karma::format_delimited(karma::auto_, ';', roundtrip) << "\n";
}

长话短说

按照快速取胜的方式使用 Boost Serialization;你会得到

  • 以更小的努力获得更高的鲁棒性
  • 更多的灵 active ,更少的努力
  • 缩短编译时间

spirit 的好处是:

  • 对序列化格式的绝对控制
  • 易于解析人类可读/可写的格式
  • 只有标题的库

关于c++ - 将 boost 序列化集成到现有代码中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21990926/

相关文章:

c++ - 解决 boost.python 中的重载

c++ - 对数组中的整数进行排序。但它不适用于某些情况

c++ - “IMG_Load”未在此范围 SDL 2 中声明

c# - 如何使用默认命名空间反序列化 xml?

c++ - 帮我解决这个调用仿函数的 boost::lambda::if_then 表达式

c++ - std::vector<float> 成员的 boost 序列化/反序列化失败

c++ - 在 ABBYY SDK 中获取字符边界框和置信度

c++ - 如何在LLVM中了解 'nullptr'的源代码?

c# - 将 List<String> 编码为普通 String 并将其解码回来的最简单方法是什么?

java - 为什么 Serialized 被称为接口(interface)?