0

I haven't been able to find any docs on how to serialize a unique_ptr to an array. Any help would be great.

struct Counter{
  int index;
  unique_ptr<char []> name;

    template<class Archive>
    void serialize(Archive & archive){
        archive(index, name ); // serialize things by passing them to the archive
    }
};

How it is assigned.

auto buffer = std::unique_ptr<char[]>(new char[BUFFER_SIZE]);
instance.name = std::move(buffer);
jww
  • 97,681
  • 90
  • 411
  • 885
  • 1
    You probably don't want to serialize `std::unique_ptr`, only the data is stores. – Yksisarvinen Jun 11 '19 at 19:25
  • How can I tell cereal to only serialize the array the unique_ptr is pointing to? – bobo7788 Jun 11 '19 at 19:29
  • `buffer.get()` retrieves the `char*`. – jww Jun 11 '19 at 19:41
  • Correct, but Cereal doesn't work with raw pointers – bobo7788 Jun 11 '19 at 19:44
  • 2
    Afaik, you can't extract the number of elements you have in the `char[]` so Cereal won't know now many `char`s to serialize. You could perhaps use a `std::string` or `std::vector` instead? That would make the `unique_ptr` redundant as well. – Ted Lyngmo Jun 11 '19 at 20:40
  • Thanks, a vector will work! But now I'm just curious if using a unique_ptr like this is even possible in Cereal – bobo7788 Jun 12 '19 at 15:08
  • I don't know Cereal, but my guess is that any `unique_ptr` owning an array (`[]`) will be very hard for it to serialize. It has no way of telling how many elements there are in the array. Perhaps it works on `unique_ptr`s holding a single element though. Edit: Found this: [Cereal - Pointers](https://uscilab.github.io/cereal/pointers.html) – Ted Lyngmo Jun 12 '19 at 19:17

1 Answers1

0

You can do it, but it needs some extra work. It differs depending on the type of the archive.

For text-based archives (e.g., XMLOutputArchive/XMLInputArchive and JSONOutputArchive/JSONInputArchive) you can use the saveBinaryValue() / loadBinaryValue() (http://uscilab.github.io/cereal/assets/doxygen/classcereal_1_1JSONOutputArchive.html).

Here's a complete example:

#include <iostream>
#include <memory>
#include <cereal/archives/xml.hpp>
#include <cereal/cereal.hpp>

struct Counter
{
  static constexpr std::size_t BUFFER_SIZE = 12;

  int index{};
  std::unique_ptr<char[]> name;

  Counter() = default;

  Counter(int i)
    : index{i},
      name{new char[BUFFER_SIZE]}
  {}

  template<class Archive>
  void load(Archive& archive)
  {
    archive(index);
    name.reset(new char[BUFFER_SIZE]);
    archive.loadBinaryValue(name.get(), BUFFER_SIZE * sizeof(decltype(name[0])));
  }

  template<class Archive>
  void save(Archive& archive) const
  {
    archive(index);
    archive.saveBinaryValue(name.get(), BUFFER_SIZE * sizeof(decltype(name[0])));
  }
};

int main()
{
  cereal::XMLOutputArchive archive(std::cout);
  Counter c(42);
  archive(CEREAL_NVP(c));
}

If you are using BinaryOutputArchive / BinaryInputArchive or PortableBinaryOutputArchive / PortableBinaryInputArchive the functions become saveBinary() and loadBinary() (http://uscilab.github.io/cereal/assets/doxygen/classcereal_1_1PortableBinaryOutputArchive.html).

For those, you can also wrap your array using binary_data():

 template<class Archive>
 void save(Archive& archive) const
 {
   archive(index, cereal::binary_data(name.get(), BUFFER_SIZE));
 }
ipapadop
  • 1,432
  • 14
  • 19