Сериализация с Cereal для полиморфного класса с использованием виртуального наследования

Я пытаюсь сериализовать и десериализовать полиморфный класс (с виртуальным наследованием) с помощью Cereal 1.1.2. Я получаю сообщение «Нарушение доступа - нет данных RTTI!» исключение, когда я пытаюсь преобразовать его в производный класс после его десериализации. Он отлично работает, когда я использую обычное наследование вместо виртуального. Я уже включил RTTI (/ GR) в настройках проекта в Visual Studio 2013 Community Edition. Вот мой код:

class Boogie
{
    friend class cereal::access;
    virtual void virtualFunction() {}
    int boogieInt = 3;
    template<class Archive>
    void serialize(Archive & archive)
    {
        archive(boogieInt);
    }
};

class Booga : virtual public Boogie
{
    friend class cereal::access;
public:
    void virtualFunction() {}
    int boogaInt = 2;
    template<class Archive>
    void serialize(Archive & archive)
    {
        archive(cereal::virtual_base_class<Boogie>(this), boogaInt);
    }
};

CEREAL_REGISTER_TYPE(Booga);

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        {
            std::shared_ptr<Boogie> boogie = std::make_shared<Booga>();
            std::ofstream ofs("Booga.txt");
            cereal::BinaryOutputArchive archive(ofs);
            archive(boogie);
            ofs.close();
        }

        std::shared_ptr<Boogie> deBoogie;
        std::ifstream ifs("Booga.txt");
        cereal::BinaryInputArchive iarchive(ifs);
        iarchive(deBoogie);

        std::shared_ptr<Booga> outBooga = std::dynamic_pointer_cast<Booga>(deBoogie);

        std::cout << outBooga->boogaInt << std::endl;

        std::cin.get();
    }
    catch (std::exception e)
    {
        std::cout << "EXCEPTION" << std::endl;
        std::cout << e.what() << std::endl;
    }
    return 0;
}

person adriank    schedule 27.08.2015    source источник
comment
Для меня ваш пример просто segfaults, поскольку он не может преобразовать десериализованный умный указатель в дочерний класс ...   -  person ForEveR    schedule 27.08.2015
comment
Небольшой комментарий - вы всегда должны убедиться, что архивы уничтожены, прежде чем что-либо делать с результатами. Они будут уничтожены, когда выйдут из поля зрения. Дополнительные сведения см. В документации.   -  person Azoth    schedule 25.09.2015


Ответы (1)


Ваша проблема в том, что вы сохраняете и загружаете разные типы - ваш код загрузки должен отражать ваш код сохранения.

Также обратите внимание, что здесь вам не нужно использовать виртуальное наследование, поскольку вы производите только от одного родительского класса - см. здесь, чтобы узнать об этом подробнее). Кроме того, пожалуйста, посмотрите мой комментарий к вашему сообщению о том, как правильно использовать архивы в формате RAII.

Ваш вывод может быть указан как:

std::shared_ptr<Boogie> data = std::make_shared<Booga>();
archive( data ); // data is actually a Booga but we hold it in a Boogie ptr

Обратите внимание, что я назначил объекту Boogie, хотя я выделил указатель Booga - это, по сути, весь смысл полиморфизма, и, если вам это не нужно, не используйте полиморфизм.

Теперь, когда мы выполняем загрузку, мы загружаемся в тот же тип, который мы сериализовали:

std::shared_ptr<Boogie> data;
archive( data ); // data is actually a Booga object because of polymorphism

Просто убедитесь, что типы переменных, которые вы фактически передаете в архив, идентичны, независимо от того, что они на самом деле связаны с полиморфизмом.

person Azoth    schedule 25.09.2015
comment
Я пробовал делать то, что вы указали раньше (назначить в Boogie, но выделить Booga), но он все равно вылетает, когда я пытаюсь преобразовать его в Booga. Я также пробовал добавить виртуальную функцию в Boogie и переопределить ее в Booga, и когда я вызываю ее после десериализации, программа вылетает. Мне нужно виртуальное наследование, потому что я портирую код с Java, а некоторые классы имеют ромбовидную структуру, которую я не знаю, как разрешить без виртуального наследования. Все работает, если убрать виртуальное наследование. - person adriank; 28.09.2015
comment
Я также заключил архивирование в блок, чтобы архив был уничтожен. - person adriank; 28.09.2015