Boost.Serialization
ライブラリ
Boost.Serialization
概要
Boost.Serializationは、C++プログラムのオブジェクトをバイトシーケンスに変換し、保存・復元を可能にする包括的なシリアライゼーションライブラリです。任意のC++データ構造を可逆的にバイトシーケンスに分解し、別のプログラムコンテキストで同等の構造を再構築できます。オブジェクトの永続化、リモートパラメータパッシング、その他のシリアライゼーションが必要な機能の実装に使用されます。
詳細
Boost.Serializationは、Boostライブラリコレクションの一部として、産業標準レベルの品質と信頼性を提供します。非侵入的なシリアライゼーション、自動的なポインタ追跡、包括的なバージョン管理、複数のアーカイブ形式のサポートなど、エンタープライズアプリケーションに必要なすべての機能を備えています。
主な特徴:
- 複数のアーカイブ形式: テキスト、バイナリ、XMLアーカイブをサポート
- 非侵入的設計: 既存クラスの変更不要でシリアライゼーション可能
- 自動ポインタ処理: ポインタの追跡と循環参照の処理を自動化
- 完全なSTLサポート: すべてのSTLコンテナに対する組み込みサポート
- バージョニング: クラスごとの独立したバージョン管理
- ポリモーフィズムサポート: 基底クラスポインタ経由での派生クラスのシリアライゼーション
- クロスプラットフォーム: 32/64ビット、Windows、Linux、Solaris等で動作
- スレッドセーフ: 異なるアーカイブインスタンスの同時読み書きが可能
- 配列最適化: 同種データの連続配列に対する最適化
アーカイブインターフェース:
- すべてのアーカイブクラスのインターフェースは同一
- 一度シリアライゼーションを定義すれば、任意のアーカイブタイプで使用可能
- 新しいアーカイブタイプの作成が容易
- XMLとして有用な形式でシリアライズデータを表現可能
メリット・デメリット
メリット
- 産業標準の品質: Boostライブラリとしての高い品質と信頼性
- 包括的な機能: エンタープライズレベルの要求に対応する完全な機能セット
- 成熟度: 長年の実績と安定性、豊富なドキュメント
- 非侵入的: ライブラリクラスを含む既存クラスの変更不要
- ポインタの自動処理: 複雑なデータ構造も安全にシリアライズ
- 優れた拡張性: カスタムアーカイブやシリアライザの作成が容易
- 大規模コミュニティ: 豊富な情報とサポート
- 標準化への影響: C++標準化への貢献実績
デメリット
- 学習曲線: 豊富な機能ゆえに、完全な理解には時間が必要
- コンパイル時間: テンプレートの多用によりコンパイル時間が増加
- バイナリサイズ: リンクされるライブラリのサイズが大きい
- パフォーマンス: 一部の軽量ライブラリと比較して処理速度が劣る場合がある
- 依存関係: Boostライブラリ全体への依存(部分的な使用も可能)
- モダンC++対応: C++11以降の機能への対応が保守的
参考ページ
書き方の例
基本的なシリアライゼーション
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
class Person {
private:
friend class boost::serialization::access;
std::string name;
int age;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & name;
ar & age;
}
public:
Person() {}
Person(const std::string& n, int a) : name(n), age(a) {}
void print() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
int main() {
// オブジェクトの保存
{
Person person("山田太郎", 30);
std::ofstream ofs("person.txt");
boost::archive::text_oarchive oa(ofs);
oa << person;
}
// オブジェクトの読み込み
{
Person person;
std::ifstream ifs("person.txt");
boost::archive::text_iarchive ia(ifs);
ia >> person;
person.print();
}
return 0;
}
STLコンテナのシリアライゼーション
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/string.hpp>
struct Employee {
std::string name;
std::string department;
double salary;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & name & department & salary;
}
};
class Company {
private:
friend class boost::serialization::access;
std::string company_name;
std::vector<Employee> employees;
std::map<std::string, int> department_count;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & company_name;
ar & employees;
ar & department_count;
}
public:
Company() {}
Company(const std::string& name) : company_name(name) {}
void addEmployee(const Employee& emp) {
employees.push_back(emp);
department_count[emp.department]++;
}
};
int main() {
Company company("テック株式会社");
company.addEmployee({"佐藤", "開発部", 500000});
company.addEmployee({"鈴木", "営業部", 450000});
company.addEmployee({"田中", "開発部", 550000});
// バイナリアーカイブで保存
{
std::ofstream ofs("company.dat", std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << company;
}
// 読み込み
Company loaded_company;
{
std::ifstream ifs("company.dat", std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
ia >> loaded_company;
}
return 0;
}
ポインタとポリモーフィズム
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
// 基底クラスの処理
}
};
class Circle : public Shape {
private:
friend class boost::serialization::access;
double radius;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & boost::serialization::base_object<Shape>(*this);
ar & BOOST_SERIALIZATION_NVP(radius);
}
public:
Circle() : radius(0) {}
Circle(double r) : radius(r) {}
double area() const override {
return 3.14159 * radius * radius;
}
};
class Rectangle : public Shape {
private:
friend class boost::serialization::access;
double width, height;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & boost::serialization::base_object<Shape>(*this);
ar & BOOST_SERIALIZATION_NVP(width);
ar & BOOST_SERIALIZATION_NVP(height);
}
public:
Rectangle() : width(0), height(0) {}
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override {
return width * height;
}
};
// 派生クラスの登録
BOOST_CLASS_EXPORT(Circle)
BOOST_CLASS_EXPORT(Rectangle)
int main() {
std::vector<std::shared_ptr<Shape>> shapes;
shapes.push_back(std::make_shared<Circle>(5.0));
shapes.push_back(std::make_shared<Rectangle>(4.0, 6.0));
// XMLアーカイブで保存
{
std::ofstream ofs("shapes.xml");
boost::archive::xml_oarchive oa(ofs);
oa << BOOST_SERIALIZATION_NVP(shapes);
}
// 読み込み
std::vector<std::shared_ptr<Shape>> loaded_shapes;
{
std::ifstream ifs("shapes.xml");
boost::archive::xml_iarchive ia(ifs);
ia >> BOOST_SERIALIZATION_NVP(loaded_shapes);
}
for (const auto& shape : loaded_shapes) {
std::cout << "Area: " << shape->area() << std::endl;
}
return 0;
}
バージョニング
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/version.hpp>
class Document {
private:
friend class boost::serialization::access;
std::string title;
std::string content;
std::string author; // バージョン1で追加
int revision_count; // バージョン2で追加
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & title;
ar & content;
if (version >= 1) {
ar & author;
}
if (version >= 2) {
ar & revision_count;
}
}
public:
Document() : revision_count(0) {}
Document(const std::string& t, const std::string& c)
: title(t), content(c), author("Unknown"), revision_count(1) {}
};
// クラスのバージョンを指定
BOOST_CLASS_VERSION(Document, 2)
int main() {
Document doc("技術文書", "Boost.Serializationの使い方について...");
// 保存
{
std::ofstream ofs("document.txt");
boost::archive::text_oarchive oa(ofs);
oa << doc;
}
// 異なるバージョンのファイルも読み込み可能
Document loaded_doc;
{
std::ifstream ifs("document.txt");
boost::archive::text_iarchive ia(ifs);
ia >> loaded_doc;
}
return 0;
}
非侵入的シリアライゼーション
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/split_free.hpp>
// サードパーティのクラス(変更不可)
class ThirdPartyClass {
int private_data;
public:
ThirdPartyClass() : private_data(0) {}
ThirdPartyClass(int data) : private_data(data) {}
int getData() const { return private_data; }
void setData(int data) { private_data = data; }
};
// 非侵入的シリアライゼーション関数
namespace boost {
namespace serialization {
template<class Archive>
void save(Archive & ar, const ThirdPartyClass & obj, const unsigned int version) {
int data = obj.getData();
ar & data;
}
template<class Archive>
void load(Archive & ar, ThirdPartyClass & obj, const unsigned int version) {
int data;
ar & data;
obj.setData(data);
}
}
}
// save/loadの分割を指定
BOOST_SERIALIZATION_SPLIT_FREE(ThirdPartyClass)
int main() {
ThirdPartyClass obj(42);
// 保存
{
std::ofstream ofs("thirdparty.txt");
boost::archive::text_oarchive oa(ofs);
oa << obj;
}
// 読み込み
ThirdPartyClass loaded_obj;
{
std::ifstream ifs("thirdparty.txt");
boost::archive::text_iarchive ia(ifs);
ia >> loaded_obj;
}
std::cout << "Loaded data: " << loaded_obj.getData() << std::endl;
return 0;
}
カスタムアーカイブの使用
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <sstream>
struct Configuration {
std::string app_name;
int version;
std::vector<std::string> modules;
template<class Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & app_name & version & modules;
}
};
// ストリームベースのシリアライゼーション
std::string serializeToString(const Configuration& config) {
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
oa << config;
return oss.str();
}
Configuration deserializeFromString(const std::string& data) {
std::istringstream iss(data);
boost::archive::text_iarchive ia(iss);
Configuration config;
ia >> config;
return config;
}
int main() {
Configuration config{"MyApp", 1, {"Core", "UI", "Network"}};
// 文字列にシリアライズ(ネットワーク送信などに利用可能)
std::string serialized = serializeToString(config);
std::cout << "Serialized: " << serialized << std::endl;
// 文字列からデシリアライズ
Configuration restored = deserializeFromString(serialized);
return 0;
}