ま、そんなところで。

ニッチな技術系メモとか、車輪を再発明してみたりとか.

C++でMessagePackを使ってみる(1)〜 基本の使い方 〜

仕事でMessagePack - C/C++を使うことがあったのでメモ.

MessagePackって何?

様々なプラットフォームで利用できるオープンソースシリアライズ仕様.
このC/C++実装版は、テンプレートベースのModern C++で記述されていて、ヘッダをインクルードするだけで簡単にプロジェクトに取り込むことができます.

https://msgpack.org/ - 公式サイト

https://github.com/msgpack/msgpack-c - C/C++向け実装

基本的な使い方

ヘッダのインクルード

C向けのインタフェースとC++用インタフェースがあるのでC++向けのヘッダをincludeする.

#include <msgpack/msgpack.hpp>

使ってみよう

対象クラスの定義

以下の条件を満たすように定義.

  • 引数なしデフォルトコンストラクタがpublic
  • MSGPACK_DEFINEで対象変数を指定
#include <iostream>
#include <string>

// 対象クラス
class Hoge {
public:
    // デシリアライズ用にデフォルトコンストラクタを用意しておく
    Hoge()
    : hoge_(0)
    , fuga_("HogeFuga")
    { }

    // パラメータ設定付きコンストラクタ
    Hoge(int hoge, std::string fuga)
    : hoge_(hoge)
    , fuga_(std::move(fuga))
    { }

    // シリアライズ設定. 対象とするメンバ変数を指定する.
    MSGPACK_DEFINE(hoge_, fuga_);
private:
    int hoge_;
    std::string fuga_;
};

ただし、MESSAGE_DEFINEできるのは MessagePackがサポートする型, もしくは、MESSAGE_DEFINEがメンバに定義された型 に限られるので注意.
デフォルトでサポートされている型は, predefined adaptorsを参照.

シリアライズ

基本としてpackerを使ってシリアライズする.

Hoge hoge;
     :
// シリアライズデータ用のバッファ
msgpack::sbuffer buffer;
// シリアライズ
msgpack::pack(buffer, hoge);
     :
// シリアライズされたデータ
char* dataptr = buffer.data();
size_t data_size   = buffer.size();

これだけ.
msgpack::pack はテンプレート関数になっていて、第1引数はメンバに void write(const char*, size_t) をもつオブジェクトであれば何でも良い.
なので、std::ostream, std::fstream, std::stringstream なんかでもOK.
状況に応じて使い分けする.

シリアライズ

msgpack::unpack を使う.

Hoge restored;
try {
    // シリアライズデータ
    char* pdata   = buffer.data();
    size_t data_size   = buffer.size();
    // シリアライズデータを読み出す
    msgpack::object_handle hd = msgpack::unpack(pdata, data_size);
    const msgpack::object& obj = hd.get();
    // デシリアライズ
    obj.convert(restored);
}
catch (std::bad_cast&) {
    // デシリアライズ時に型の不一致を検出するとbad_cast例外
        :
}

とても手軽に使用できるのが魅力的ですね!


参考記事