boost::serializationでほげほげうまうま

オブジェクトをまるごとファイルに書きだしたりネットワークに送ったりしたいとき内容を直列化し再構築することやその仕組みをシリアライズと呼び,boostではserializationライブラリによって実現できます.
どのような形のデータ列に落としこむか?という話で,boost::serializationはテキスト,XML,バイナリの3種類がサポートされています.

分かりやすいページ

僕なんかの記事よりは,他の方の記事を見たほうがいいと思います.

サンプルプログラム

ということでこうやって使おうというサンプル.
次のようなエッセンスを織り込んで書きました.

  • XMLでシリアライズできるように定義したクラス
  • テキスト・バイナリ・XMLでのシリアライズと逆シリアライズのデモ

    • XMLでシリアライズできるように定義すれば全部の形式でシリアライズ・逆シリアライズできてウマー
  • STLコンテナのシリアライズ
  • ネストした自作クラスのシリアライズ

    • informationクラスのオブジェクトがinner_informationクラスのオブジェクトを持ってる状態
  • ファイルやネットワークには書き出しません.内部的に変換して逆変換してるだけです.
そーす

#include
#include
#include

#include
#include
#include

#include
#include
#include

#include
#include

#include
#include

using namespace std;
using namespace boost;

//入れ子のクラス階層でもシリアライズできる
class inner_information
{
friend class boost::serialization::access;
friend ostream& operator<<(ostream&, const inner_information&); int inner_value; template
void serialize(Archive& ar, unsigned int ver)
{
static_cast(ver);
ar & boost::serialization::make_nvp(“inner_value”, inner_value);
}

public:

inner_information()
{ }

inner_information(int n)
:inner_value(n)
{ }
};

ostream& operator<<(ostream& os, const inner_information& inf) { return os << " value: " << inf.inner_value << endl; } class information { friend class boost::serialization::access; friend ostream& operator<<(ostream&, const information&); int value; string str; vector vec;
inner_information inf;

template
void serialize(Archive& ar, unsigned int ver)
{
static_cast(ver);
ar & boost::serialization::make_nvp(“Value”, value);
ar & boost::serialization::make_nvp(“String”, str);
ar & boost::serialization::make_nvp(“Vector”, vec);
ar & boost::serialization::make_nvp(“InnerInformation”, inf);
}

public:

information()
{ }

information(int val, string s, const vector& v, const inner_information& i)
:value(val), str(s), vec(v), inf(i)
{ }
};

ostream& operator<<(ostream& os, const information& info) { os << " > value: ” << info.value << endl; os << " > str: ” << info.str << endl; os << " > vec:”;
for(int t : info.vec)
os << " " << t; os << endl; os << " > inf:” << info.inf; return os; } //////////////////////////////////////// // テキストでシリアライズ・逆シリアライズ //////////////////////////////////////// void serialize_into_text(const information &info) { cout << "***** テキストへのシリアライズ *****" << endl; string result; cout << "入力:" << endl << info; { stringstream sstr; boost::archive::text_oarchive ar(sstr); ar << info; cout << "シリアライズ結果:" << endl; result = sstr.str(); cout << result << endl; } { information inf; stringstream sstr(result); boost::archive::text_iarchive ar(sstr); ar >> inf;

cout << "逆シリアライズ結果:" << endl << inf; } } //////////////////////////////////////// // XMLでシリアライズ・逆シリアライズ //////////////////////////////////////// void serialize_into_xml(const information& info) { cout << "***** XMLへのシリアライズ *****" << endl; string result; cout << "入力:" << endl << info; { stringstream sstr; boost::archive::xml_oarchive ar(sstr); ar << boost::serialization::make_nvp("information", info); cout << "シリアライズ結果:" << endl; result = sstr.str(); cout << result << endl; } { information inf; stringstream sstr(result); boost::archive::xml_iarchive ar(sstr); ar >> boost::serialization::make_nvp(“information”, inf);

cout << "逆シリアライズ結果:" << endl << inf; } } //////////////////////////////////////// // バイナリでシリアライズ・逆シリアライズ //////////////////////////////////////// void serialize_into_binary(information& info) { cout << "***** バイナリへのシリアライズ *****" << endl; string result; cout << "入力:" << endl << info; { stringstream sstr; boost::archive::binary_oarchive ar(sstr); ar << info; cout << "シリアライズ結果:" << endl; result = sstr.str(); for(int i = 0; i < result.size(); i++) printf("%c", result.c_str()[i]); cout << endl; } { information inf; stringstream sstr(result); boost::archive::binary_iarchive ar(sstr); ar >> inf;

cout << "逆シリアライズ結果:" << endl << inf; } } int main() { information info(120, "hogehoge", {1, 3, 5, 7, 9}, inner_information(15)); serialize_into_text(info); serialize_into_xml(info); serialize_into_binary(info); } [/cpp]

コンパイル方法

gcc 4.4.3とboost 1.47.0です.あと,上のコードはC++0xサポートが必要です.
serializationライブラリはライブラリのリンクが必要です.
まとめると,

% g++ prog.cpp -std=c++0x -lboost_serialization

でコンパイルします.

実行結果

で,実行結果.
まずはテキストへのシリアライズ.

 ***** テキストへのシリアライズ *****
入力:
 > value: 120
 > str: hogehoge
 > vec: 1 3 5 7 9
 > inf: value: 15
シリアライズ結果:
22 serialization::archive 9 0 0 120 8 hogehoge 5 0 1 3 5 7 9 0 0 15
逆シリアライズ結果:
 > value: 120
 > str: hogehoge
 > vec: 1 3 5 7 9
 > inf: value: 15

次はXMLへのシリアライズ

 ***** XMLへのシリアライズ *****
入力:
 > value: 120
 > str: hogehoge
 > vec: 1 3 5 7 9
 > inf: value: 15
シリアライズ結果:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="9">
<information class_id="0" tracking_level="0" version="0">
	<Value>120</Value>
	<String>hogehoge</String>
	<Vector>
		<count>5</count>
		<item_version>0</item_version>
		<item>1</item>
		<item>3</item>
		<item>5</item>
		<item>7</item>
		<item>9</item>
	</Vector>
	<InnerInformation class_id="2" tracking_level="0" version="0">
		<inner_value>15</inner_value>
	</InnerInformation>
</information>

逆シリアライズ結果:
 > value: 120
 > str: hogehoge
 > vec: 1 3 5 7 9
 > inf: value: 15

最後はバイナリへのシリアライズ

 ***** バイナリへのシリアライズ *****
入力:
 > value: 120
 > str: hogehoge
 > vec: 1 3 5 7 9
 > inf: value: 15
シリアライズ結果:
1600000073657269616c697a6174696f6e3a3a617263686976650900040404080100000000000000007800000008000000686f6765686f676505000000010000000300000005000000070000000900000000000000000f000000
逆シリアライズ結果:
 > value: 120
 > str: hogehoge
 > vec: 1 3 5 7 9
 > inf: value: 15

どれも正しくシリアライズ・逆シリアライズできてますね.
素晴らしい.

C#ずるい

C#だとXmlSerializerというのがあって,デフォルトコンストラクタをもってて全てのデータはフィールドかメンバで設定できるクラスなら他に何もしなくてもXMLにシリアライズ・逆シリアライズできたりします.ずるい.
あと,BinaryFormatterというのもあって,アノテーション…じゃない,属性を付ければそれだけでどんな型でもシリアライズ・逆シリアライズできます.超ずるい.
そのへんのまとめた記事を,旧ブログMr.Exception シリアライズまとめに書いてたりします.このへんを自作するとリフレクション周りの理解が進んで非常によいです.あとユニットテストフレームワークの自作も同じく.
むむむ,「シリアライズ」がゲシュタルト崩壊してきた(@ω@)

コメントを残す

メールアドレスが公開されることはありません。