C++オブジェクトの直列化 (シリアライズ)

(2009.5.11 新規作成。2011.8 加筆、新規公開。)

C++オブジェクトをネットワーク経由などでやり取りしたりするための、直列化 (シリアライズ) について。

概要

Windows向けにC++で開発する場合、MFC (Microsoft Foundation Classes) にはシリアライズ機能が含まれます。

boostにもポータブルなシリアリゼーション機能があり、MFCが利用できない場合、これが使えます。

クラス定義

直列化したいオブジェクトのクラスで、次のようにします。

C++
[RAW]
  1. #include <list>
  2. #include <string>
  3. // #include <boost/serialization/list.hpp>
  4. // #include <boost/serialization/string.hpp>
  5. #include <boost/serialization/version.hpp>
  6. #include <boost/serialization/split_member.hpp>
  7. class BusStop;
  8. class BusRoute {
  9. // おまじない
  10. friend class boost::serialization::access;
  11. BOOST_SERIALIZATION_SPLIT_MEMBER()
  12. std::list<BusStop*> stops;
  13. std::string driver_name;
  14. // 必ずprivate.
  15. template <class Archive>
  16. void save(Archive& ar, unsigned int version) const {
  17. ar & driver_name;
  18. ar & stops;
  19. }
  20. // 必ずprivate.
  21. template <class Archive>
  22. void load(Archive& ar, unsigned int version) {
  23. if (version > 0)
  24. ar & driver_name;
  25. ar & stops;
  26. }
  27. };
  28. BOOST_CLASS_VERSION(BusRoute, 1)

何か特定のクラスのサブクラスにする必要はありません。save(), load() を定義するのと、いくつかのおまじないを書きます。

save(), load() では、最初の引数としてアーカイブなどが渡されます。& 演算子で追記、または読み込みを行います。

また、version も引数として渡されるため、それによって保存、再生する内容を変えることもできます。

オブジェクトの保存

オブジェクトを保存するには、boost::archive::binary_oarchive などのアーカイブクラスを通じて、ストリームに書き込みます。

例えば、シリアライズ可能な型Typのオブジェクトobjを受け取って、シリアライズし、MPIで送信するコードは、次のようになります。

C++
[RAW]
  1. template <typename Typ>
  2. void isend_obj( int dest_node, int tag, const Typ& obj,
  3. std::vector<MPI_Request>* reqs )
  4. {
  5. std::ostringstream oss;
  6. boost::archive::binary_oarchive oa(oss);
  7. oa << obj;
  8. int32_t len = oss.str().size();
  9. printf("len = %d\n", len); // DEBUG
  10. MPI_Request req;
  11. mMPI_CHECK_RESULT( MPI_Isend(&len, 1, MPI_INT32_T, dest_node, tag,
  12. MPI_COMM_WORLD, &req) );
  13. reqs->push_back(req);
  14. mMPI_CHECK_RESULT( MPI_Isend((void*) oss.str().data(), len, MPI_BYTE,
  15. dest_node, tag + 1, MPI_COMM_WORLD, &req) );
  16. reqs->push_back(req);
  17. }

アーカイブクラスは仲立ちをし、シリアライズされたデータはストリームに書き込まれます。

ライブラリとのリンク

boostのシリアライズ機能は、それだけで一つのライブラリとのリンクが必要です。リンカに -lboost_serialization オプションを加えます。

外部リンク