2

I'm trying to use Cereal to serialize an object without default constructor. Storing such objects directly or via smart pointer works. However, when I put the object into a container, it no longer compiles:

error: no matching function for call to ‘Node::Node()’

Is there a way to get cereal to store/restore vectors of objects without default constructor?

My test code:

#include <fstream>
#include <cereal/archives/json.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/types/vector.hpp>


class Node {
public:
    Node(int* parent) {};

    int value_1;

    template<class Archive>
    void serialize(Archive& archive) {
        archive(
                CEREAL_NVP(value_1)
        );
    }

    template<class Archive>
    static void load_and_construct(Archive& archive, cereal::construct<Node>& construct) {
        construct(nullptr);
        construct->serialize(archive);
    }
};

int main() {
    std::string file_path = "../data/nodes.json";
    Node node_1{nullptr};  // this would serialize

    std::vector<Node> nodes;  // this does not
    nodes.push_back(Node{nullptr});
    nodes.push_back(Node{nullptr});

    std::vector<std::unique_ptr<Node>> node_ptrs;  // this would serialize
    node_ptrs.push_back(std::make_unique<Node>(nullptr));
    node_ptrs.push_back(std::make_unique<Node>(nullptr));

    {  //store vector
        std::ofstream out_file(file_path);
        cereal::JSONOutputArchive out_archive(out_file);
        out_archive(CEREAL_NVP(nodes));
    }

    {  // load vector
        std::ifstream in_file(file_path);
        cereal::JSONInputArchive in_archive(in_file);
        in_archive(nodes);
    }

    return 0;
}
BoshWash
  • 5,320
  • 4
  • 30
  • 50

1 Answers1

1

As far as I understand the way this library works, there is no way to deserialize something that doesn't have a default constructor at least for dynamically allocated objects.

The logic under this is the following:

  1. You need to deserialize vector<Node>
  2. In order to do that you need to allocate an appropriate amount of memory
  3. cereal doesn't know about the constructor and can't properly allocate object memory by itself
  4. In order to provide a proper object building it requires the default constructor
Alex
  • 9,891
  • 11
  • 53
  • 87
  • 1
    Imagine the scenario of loading a type that has no default constructor. The interface to cereal's serialization requires you to pass a reference to the object to be instantiated with serialized data. In the case of no default constructor, you (the user) must have already initialized such an object before cereal even sees it. The alternative is for cereal to do the actual construction of the object, which can only happen with dynamically created (i.e. pointers) objects, so that cereal can pre-load the arguments to pass to the constructor, as in `load_and_construct`. – Azoth May 16 '17 at 22:02