Serializing Maps of Polymorphic Objects

I have a std::map where the value type is a pointer to the base Character class, but it actually points to derived Monster objects. How can I serialize and deserialize this map correctly?

To correctly serialize and deserialize a std::map where the value type is a base class pointer (Character*) pointing to derived class objects (Monster), follow these steps:

Step One: Include the necessary cereal headers:

#include <cereal/archives/binary.hpp>
#include <cereal/types/map.hpp>
#include <cereal/types/polymorphic.hpp>

Step Two: In your derived Monster class, ensure you have the serialize function defined and register the polymorphic relationship:

class Monster : public Character {
  // ...

  template <class Archive>
  void serialize(Archive& ar) {
    ar(cereal::base_class<Character>(this));
    // ...
  }
};

CEREAL_REGISTER_TYPE(Monster);
CEREAL_REGISTER_POLYMORPHIC_RELATION(Character, Monster);

Step Three: Create your map with base pointers to derived objects:

std::map<int, std::unique_ptr<Character>> enemies;
enemies[1] = std::make_unique<Monster>();
enemies[2] = std::make_unique<Monster>();

Step Four: Serialize the map using a cereal output archive:

std::ofstream file("enemies.dat");
cereal::BinaryOutputArchive archive(file);
archive(enemies);

Step Five: Deserialize the map using a cereal input archive:

std::ifstream file("enemies.dat");
cereal::BinaryInputArchive archive(file);
std::map<int, std::unique_ptr<Character>> loadedEnemies;
archive(loadedEnemies);

After deserialization, loadedEnemies will contain pointers to the correct derived Monster objects, even though the map's value type is std::unique_ptr<Character>. Cereal's polymorphic serialization handles the type restoration.

Note: Make sure to use smart pointers like std::unique_ptr in the map to avoid manual memory management and resource leaks.

A complete example is below:

#include <cereal/archives/binary.hpp>
#include <cereal/types/map.hpp>
#include <cereal/types/polymorphic.hpp>
#include <fstream>
#include <iostream>
#include <map>
#include <memory>

class Character {
 public:
  virtual ~Character() = default;

  std::string name;

 protected:
  friend class cereal::access;

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

class Monster : public Character {
 public:
  int health;

 private:
  friend class cereal::access;

  template <class Archive>
  void serialize(Archive& ar) {
    ar(cereal::base_class<
      Character>(this), health);
  }
};

CEREAL_REGISTER_TYPE(Monster);
CEREAL_REGISTER_POLYMORPHIC_RELATION(Character,
  Monster);

int main() {
  std::map<int, std::unique_ptr<
    Character>> enemies;
  enemies[1] = std::make_unique<Monster>();
  enemies[1]->name = "Goblin";
  dynamic_cast<Monster*>(
    enemies[1].get())->health = 50;
  enemies[2] = std::make_unique<Monster>();
  enemies[2]->name = "Orc";
  dynamic_cast<Monster*>(
    enemies[2].get())->health = 100;

  {
    std::ofstream file("enemies.dat");
    cereal::BinaryOutputArchive archive(file);
    archive(enemies);
  }

  std::map<int, std::unique_ptr<
    Character>> loadedEnemies;

  {
    std::ifstream file("enemies.dat");
    cereal::BinaryInputArchive archive(file);
    archive(loadedEnemies);
  }

  for (const auto& [id, enemy] : loadedEnemies) {
    std::cout << "ID: " << id << ", Name: "
      << enemy->name;
    if (auto monster = dynamic_cast<Monster*>(
      enemy.get())) {
      std::cout << ", Health: "
        << monster->health;
    }
    std::cout << "\n";
  }
}
ID: 1, Name: Goblin, Health: 50
ID: 2, Name: Orc, Health: 100

Binary Serialization using Cereal

A detailed and practical tutorial for binary serialization in modern C++ using the cereal library.

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Serializing Vectors of Custom Types
How can I serialize a vector of my custom Player objects using cereal?
Versioning Serialized Game Save Files
I'm working on a game and want to ensure that save files from older versions can still be loaded in newer versions. How can I handle this using cereal's versioning features?
Serializing Private Class Members with Cereal
I want to serialize private member variables of my Player class using cereal. How can I accomplish this?
Serializing Non-Default-Constructible Classes with Cereal
I have a Weapon class that requires parameters in its constructor and doesn't have a default constructor. How can I serialize and deserialize objects of this class using cereal?
Serializing Enum Classes with Cereal
I have an enum class called State in my game. How can I serialize and deserialize variables of this enum class type using cereal?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant