5

Is it possible to serialize a boost::ptr_vector instance using cereal? If so, how?

Ton van den Heuvel
  • 10,157
  • 6
  • 43
  • 82
  • 2
    I'm not intimately familiar with `ptr_vector`, but it looks like it is essentially a wrapper around `std::vector`. cereal does not support raw pointers, so I think it is unlikely you would be able to serialize a `ptr_vector` without significant changes to cereal or a complicated workaround. – Azoth Jan 30 '16 at 00:42

1 Answers1

3

It is definitely possible. You can create external save() and load() template functions on the archive and pointer type like this:

#include <iostream>
#include <sstream>
#include <boost/ptr_container/ptr_vector.hpp>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>

// Sample serializable object.
struct MyRecord {
   std::string s_;

   MyRecord(const std::string s = std::string())
      : s_(s) {
   }

   template <class Archive>
   void serialize(Archive& ar ) {
      ar(s_);
   }
};

// External save function for boost::ptr_vector<T>.
template<class Archive, class T>
void save(Archive& ar, const boost::ptr_vector<T>& pv) {
   ar(pv.size());
   for (const auto& element : pv)
      ar(element);
}

// External load function for boost::ptr_vector<T>.
template<class Archive, class T>
void load(Archive& ar, boost::ptr_vector<T>& pv) {
   size_t n;
   ar(n);

   pv.reserve(n);
   for (size_t i = 0; i < n; ++i) {
      pv.push_back(new T);
      ar(pv.back());
   }
}

int main() {
   // Serialize a boost::ptr_vector to a buffer.
   std::ostringstream os;
   {
      boost::ptr_vector<MyRecord> saved;
      saved.push_back(new MyRecord("how"));
      saved.push_back(new MyRecord("now"));
      saved.push_back(new MyRecord("brown"));
      saved.push_back(new MyRecord("cow"));

      cereal::BinaryOutputArchive oa(os);
      oa(saved);
   }

   // Serialize from the buffer.
   boost::ptr_vector<MyRecord> loaded;
   {
      std::istringstream is(os.str());
      cereal::BinaryInputArchive ia(is);
      ia(loaded);
   }

   for (const auto& element : loaded)
      std::cout << element.s_ << '\n';

   return 0;
}

This should work with any contained type that is default-constructible and is already individually serializable.

rhashimoto
  • 15,650
  • 2
  • 52
  • 80
  • .... and for which the overloads for `save` and `load` can be found in an _associated namespace_ (cf. ADL). I might add that this version has rather funny construction semantics on load. It's "ok" because ptr_vectors cannot have aliasing elements anyways – sehe Feb 01 '16 at 22:17
  • @sehe, with the funny load semantics you mean this can be done more efficiently? – Ton van den Heuvel Feb 05 '16 at 08:30
  • Actually, no, it looks fine. – sehe Feb 05 '16 at 10:49