Cereal library--从Boost到Cereal的过渡

原文翻译自:
http://uscilab.github.io/cereal/transition_from_boost.html

如果你曾经使用过Boost序列化功能,你会发现Cereal和Boost很相似。这是因为Cereal被设计时就考虑了Boost用户的使用习惯,模仿了许多Boost序列化库的语法习惯。本文是一个简要的过渡指南。请保证你已经能正常安装Cereal,并且对基本语法有一个简要的认识,可参考文章“Cereal快速入门”。

TLDR版本(TLDR??)

Cereal和Boost序列库的接口非常相似,在一些情况下可以非常迅速的将Boost库替换成Cereal。但是即便如此,Cereal和Boost还是有很大的区别的,想要了解更多继续阅读本文或者参考
http://uscilab.github.io/cereal/assets/doxygen/index.html

差异

  • Cereal在序列化时只存储非常少量的元数据(metadata)。反之Boost序列化库存储了大量的元数据,例如Boost库版本等等。Cereal则并不需要版本信息来保证序列化和反序列化时库版本一致。
  • Cereal只需要头文件即可,不再需要其他依赖库。在使用Boost时,由于Boost库繁多复杂,一个非常头疼的问题是如何保证不同机器间的Boost版本一致。但是这个问题在使用Cereal时并不存在,因为Cereal非常容易安装和使用。
  • Cereal基本支持所有的标准库。并且一些Cereal支持的标准,Boost并不支持,这包括:forward_list、memory、queue、stack、tuple、unordered_set和unordered_map。
  • Cereal不支持指针,并且需要支持C++11的编译器。但是从一个使用者的角度来看,Cereal的代码是非常简单理解和扩展的。
  • 相比Boost,Cereal更加简洁。例如,在Cereal中当把serialize函数分成load/save函数时,不需要提前使用宏声明。Cereal还使用了static_assert,提供了更加准确的错误提示。
  • Cereal和Boost使用了不同的语法规则进行序列化。Boost使用的是&,<<和>>,而在Cereal中使用的是(),例如archive(myData1,myData2)。但是为了方便,Cereal也支持Boost的语法规则。总而言之Cereal和Boost非常相似,但是读者在使用时还说要根据情况认真阅读doxygen文档以分辨其中的细小差异。

过渡的例子

要将Boost修改成Cereal,并不需要对代码进行大量修改。前文中已经提到,Cereal支持Boost的语法规则。下文中给出一个例子,示例如何从Boost转移到Cereal中。

#include <boost/archive/binary_oarchive.hpp>
#include <cereal/archives/binary.hpp>
#include <fstream>

class SomeData
{
  public:
    SomeData() = default;
    int a;
    int b;

  private:
    friend class cereal::access; // 友函数,获取版本信息
    boost::serialization::access;

    // 可选项,Cereal支持版本信息 
    //
    // 注意第二个参数从const unigned int改成了const std::uint32_t
    template <class Archive>
    void save( Archive & ar, std::uint32_t const version ) const
    {
      // Cereal支持Boost语法
      ar << a << b;
    }

    template <class Archive>
    void load( Archive & ar, std::uint32_t const version )
    {
      ar >> a;
      ar >> b;
    }

  // Cereal并不需要此处声明
  BOOST_SERIALIZATION_SPLIT_MEMBER()
};

//当使用Cereal时,由于BOOST_SERIALIZATION_SPLIT_MEMBER由于声明了一个serialize函数,会使得Cereal产生一个错误。Cereal不能同时支持load/save和serialize。

// 为解决此问题,需要临时使用一个特殊函数来保证Cereal不把Boost的宏当做错误。当你把这个宏删掉后,这个特殊函数也就没有必要再使用了。
CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( SomeData, cereal::specialization::member_load_save )

BOOST_CLASS_VERSION(SomeData, 1);
CEREAL_CLASS_VERSION(SomeData, 1); 

struct MyType
{
  int x;
  double y;
  SomeData s;

  template <class Archive>
  void serialize( Archive & ar, std::uint32_t const version )
  {
    ar & x & y; // 在Cereal中&是合法的,但并不推荐
    ar & s;
  }
};

int main()
{
  std::ofstream os("out.bin", std::ios::binary);

  // using boost
  {
    boost::archive::binary_oarchive ar(os);
    MyType m;
    ar << m; // Cereal支持Boost的语法
  }

  // using cereal
  {
    cereal::BinaryOutputArchive ar(os);
    MyType m;
    ar << m;
  }

  return 0;
}

在上述代码中,仅仅通过添加一个Cereal版本友函数,就能将Boost快速过渡到Cereal。但是当你使用Boost中的其他特性时,可能需要修改其他代码,不再赘述。
观察代码不难发现,在Boost使用load/save模式序列化,需要使用宏BOOST_MEMBER_SPLIT。但是Cereal则更人性化,直接使用即可。
不能将boost::serialization::access设置为友函数,应该将cereal::access设置为友函数,详情参照cereal/access.hpp。
在Cereal,类版本信息是一个额外信息,不是必要信息,因此在serialization函数通常将其作为第二个参数,格式为std::uint32_t const。除此之外,宏BOOST_CLASS_VERSION 在Cereal中有一个对应宏CEREAL_CLASS_VERSION。
总结,Cereal和Boost有非常多的相似之处,但是也略有差异。因此特别建议在使用时详细阅读doxygen文档。

下文把上文重写,改成了完全的Cereal格式:

#include <cereal/archives/binary.hpp>
#include <fstream>

class SomeData
{
  public:
    SomeData() = default;
    int a;
    int b;

  private:
    friend class cereal::access;

    // 版本信息是可选项
    template <class Archive>
    void save( Archive & ar, std::uint32_t const version ) const
    {
      ar( a, b ); 
    }

    template <class Archive>
    void load( Archive & ar, std::uint32_t const version )
    {
      ar( a, b );
    }
};

CEREAL_CLASS_VERSION(SomeData, 1);

struct MyType
{
  int x;
  double y;
  SomeData s;

  template <class Archive>
  void serialize( Archive & ar, std::uint32_t const version )
  {
    ar( x, y );
    ar( s );
  }
};

int main()
{
  std::ofstream os("out.bin", std::ios::binary);

  {
    cereal::BinaryOutputArchive ar(os);
    MyType m;
    ar( m );
  }

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值