Cereal library--从Boost到Cereal的过渡

来源:互联网 发布:我知主掌握明天歌谱 编辑:程序博客网 时间:2024/05/16 11:18

原文翻译自:
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;}
原创粉丝点击