C++11 序列化库 cereal
cereal —— C++11 序列化庫
介紹
cereal是一個只包含頭文件的C++序列化庫,cereal支持任何類型的數據并可以將其序列化為不同形式,例如:二進制、XML或者JSON。
cereal的設計理念是快速、輕量級和容易擴展——cereal沒有依賴第三庫而且可以輕易的將其和其他代碼相。
cereal 完整支持 C++11
cereal 已經支持 C++11 標準庫中的所有類型了,而且 cereal 也完全支持繼承和多態。為了保持 cereal 的簡潔性并不降低性能,cereal 沒有像 Boost 等庫那樣跟蹤并序列化類中所有成員變量。cereal不支持原始指針和引用對象的序列化,但智能指針是支持的。
cereal 支持眾多符合C++11標準的編譯器
cereal 使用了很多C++11與編譯器的特性。cereal 官方支持 g++4.7.3、clang++3.3、MSVC 2013或者更新的編譯器。cereal可能支持其他類型或版本的編譯器,比如ICC,但cereal不保證完全可用。在使用g++或者clang++時,cereal可以與libstdc++和libc++一起編譯與執行。
cereal 小巧且迅速
一些簡單的性能測試表名,cereal一般比Boost中的序列化庫(或者其他庫)要快,并且如果使用二進制文件存儲序列化后的對象(數據),cereal占用的空間更小,這些特點在序列化小對象時更加明顯。cereal使用了C++中最快的XML和JSON解析庫。cereal的代碼相對于其他庫如Boost而言更加容易理解且更易擴展。
cereal 是可擴展的
cereal支持將序列化后的對象保存為XML、JSON、和二進制格式。如果需要,你可以添加自己想要的序列化文件格式和其他需要被序列化的數據類型(如自定義類,cereal默認只支持標準庫中的類)。
cereal 有單元測試
為了保證庫的可用性與可靠性,我們為cereal編寫了單元測試。cereal使用了Boost 單元測試框架,所以運行這些單元測試需要配置Boost庫。
cereal 很容易使用
cereal的使用是非常簡單的,包含頭文件并編寫序列化語句既可。cereal有優秀的文檔來描述其自身的概念和代碼。cereal近最大可能在編譯時識別并報告你代碼中的錯誤。
cereal 提供了與Boost類似的語法
如果你使用過Boost中的序列化庫,那么你使用cereal是就會感覺到很熟悉,cereal的設計使得熟悉boost的用戶容易學習。cereal在對象的方法或者非成員函數中尋找序列化函數。與Boost不同,你不需要告訴cereal你序列化對象的類型。如果你曾經使用過Boost,請查看我們的遷移手冊。
下面是一個示例:
#include <cereal/types/unordered_map.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/binary.hpp>
#include <fstream>
struct MyRecord
{
uint8_t x, y;
float z;
template <class Archive>
void serialize( Archive & ar )
{
ar( x, y, z );
}
};
struct SomeData
{
int32_t id;
std::shared_ptr<std::unordered_map<uint32_t, MyRecord>> data;
template <class Archive>
void save( Archive & ar ) const
{
ar( data );
}
template <class Archive>
void load( Archive & ar )
{
static int32_t idGen = 0;
id = idGen++;
ar( data );
}
};
int main()
{
std::ofstream os("out.cereal", std::ios::binary);
cereal::BinaryOutputArchive archive( os );
SomeData myData;
archive( myData );
return 0;
}
cereal 在 BSD 協議下發行
快速入門
本小結幫助你在幾分鐘內獲得與編譯運行cereal。你唯一需要準備的是一臺安裝了符合C++11標準的編譯器,例如GCC 4.7.3、clang 3.3、MSVC 2013,或者更新的這些編譯器更新的版本。低版本的編譯器也許可以正常工作,但我們不提供這樣的保證。
獲得 cereal
你可以從github倉庫下載最新的cereal,并將頭文件放在任何你編譯器可以找到的路徑之下。cereal不需要預先構建與編譯——cereal是header-only的。
向需要序列化的對象中添加成員方法
cereal需要知道對象中的哪些成員是需要序列化的。你需要在對象中實現serialize方法來告知cereal:
struct MyClass
{
int x, y, z;
// This method lets cereal know which data members to serialize
template<class Archive>
void serialize(Archive & archive)
{
// serialize things by passing them to the archive
archive( x, y, z );
}
};
cereal提供了其他更加靈活的序列化函數,你可以在這里看到有關序列化函數的文檔。cereal也支持類版本、私有序列化方法,也支持沒有默認構造函數的類。
使用cereal自帶的序列化函數,你可以序列化C++中原始數據類型和幾乎所有標準庫中定義的類型。
選擇一種歸檔(序列化)格式
cereal暫時支持三種序列化文件格式:二進制(支持portable模式)、JSON、XML。XML和JSON方便閱讀但也會降低性能(時間與空間上消耗會更大)。
請從下面的頭文件中選擇一個你喜歡的序列化文件格式:
#include <cereal/archives/binary.hpp>
#include <cereal/archives/portable_binary.hpp>
#include <cereal/archives/xml.hpp>
#include <cereal/archives/json.hpp>
序列化你的數據
創建一個cereal歸檔對象并提供你想序列化的類。歸檔對象使用RAII方式管理資源,cereal保證在歸檔對象析構的時候將序列化數據寫進具體文檔中(也可能在析構之前)。創建歸檔對象時需要一個 std::istream或者std::ostream對象。
#include <cereal/archives/binary.hpp>
#include <sstream>
int main()
{
std::stringstream ss; // any stream can be used
{
// Create an output archive
cereal::BinaryOutputArchive oarchive(ss);
MyData m1, m2, m3;
oarchive(m1, m2, m3); // Write the data to the archive
} // archive goes out of scope, ensuring all contents are flushed
{
cereal::BinaryInputArchive iarchive(ss); // Create an input archive
MyData m1, m2, m3;
iarchive(m1, m2, m3); // Read the data from the archive
}
}
重要提示!如果你沒有閱讀上面cereal使用了RAII機制的段落,請仔細閱讀一遍。cereal中的一些歸檔對象只會在其析構的時候將數據寫進輸入輸出流對象(iostream)中。一定要保證,特別是將對象序列化時,你的歸檔對象會在你使用完成后自動析構,構造序列化數據可能是不完整的。
具名變量
cereal支持你為序列化對象命名,在你使用方便閱讀的歸檔格式(XML 或 JSON)時這個特性非常有用:
#include <cereal/archives/xml.hpp>
#include <fstream>
int main()
{
{// **注意這列大括號的作用**,大括號之外析構歸檔對象,將歸檔數據寫進對應文檔中
std::ofstream os("data.xml");
cereal::XMLOutputArchive archive(os);
MyData m1;
int someInt;
double d;
archive( CEREAL_NVP(m1), // 序列化變量 m1 時使用變量的原始名稱 'm1'
someInt, // cereal 將自動為 someInt 定義一個名字
// 序列化變量 d 時,使用用戶自定義的名字
cereal::make_nvp("this_name_is_way_better", d) );
}// 析構 archive,將數據寫進 os 中
{
std::ifstream is("data.xml");
cereal::XMLInputArchive archive(is);
MyData m1;
int someInt;
double d;
// 反序列化過程不需要指定變量名,也可以指定
archive( m1, someInt, d );
}
}
更多有關具名變量的信息可以閱讀這些文檔。
進一步學習
cereal可以做更多更復雜的序列化。cereal支持智能指針、多態、繼承等。更多信息請參考官方文檔比如,代碼文檔和官方教程。
cereal 對標準庫的支持
cereal當前支持C++中的絕大部分容器和類。引用 cereal 中對應的頭文件以實現標準庫容易和類的支持(例如:<cereal/types/vector.hpp>)。查閱 doxygen docs查看cereal所支持的所有標準庫容器和類。
模板支持
未了序列化一個標準庫中的容器或者類,你只需要包含對應的頭文件,就像#include <cereal/types/xxxx.hpp>這樣,然后使用普通的語法:
// type support
#include <cereal/types/map.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/complex.hpp>
// for doing the actual serialization
#include <cereal/archives/json.hpp>
#include <iostream>
class Stuff
{
public:
Stuff() = default;
void fillData()
{
data = { {"real", { {1.0f, 0},
{2.2f, 0},
{3.3f, 0} }},
{"imaginary", { {0, -1.0f},
{0, -2.9932f},
{0, -3.5f} }} };
}
private:
std::map<std::string, std::vector<std::complex<float>>> data;
friend class cereal::access;
template <class Archive>
void serialize( Archive & ar )
{
ar( CEREAL_NVP(data) );
}
};
int main()
{
cereal::JSONOutputArchive output(std::cout); // stream to cout
Stuff myStuff;
myStuff.fillData();
output( cereal::make_nvp("best data ever", myStuff) );
}
上面的代碼會生成下面的JSON文件:
{
"best data ever": {
"data": [
{
"key": "imaginary",
"value": [
{
"real": 0,
"imag": -1
},
{
"real": 0,
"imag": -2.9932
},
{
"real": 0,
"imag": -3.5
}
]
},
{
"key": "real",
"value": [
{
"real": 1,
"imag": 0
},
{
"real": 2.2,
"imag": 0
},
{
"real": 3.3,
"imag": 0
}
]
}
]
}
}
如果你在序列化標準庫類型時編譯器報錯,比如cereal無法找到合適的序列化方法,你可能需要檢查一下是否包含了對應的cereal頭文件。
更多有關歸檔對象和序列化函數的信息可以查閱序列化函數和歸檔對象這兩小節。
從Boost遷移到cereal
略
總結
以上是生活随笔為你收集整理的C++11 序列化库 cereal的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10天掌握webpack 4.0 优化篇
- 下一篇: Perl中DBI、DBD::mysql模