Полиморфная сериализация с ускорением

Я пытаюсь (де) сериализовать полиморфный вектор, но у меня разные проблемы с разными попытками. Весь порядок событий таков:

  • Сериализация полиморфного вектора на стороне сервера
  • Отправить сериализованную строку по сети
  • Десериализовать в новый полиморфный вектор на стороне клиента
  • Редактировать данные в векторе (включая добавление, редактирование и удаление) на стороне клиента
  • Сериализовать отредактированный полиморфный вектор на стороне клиента
  • Отправить новую сериализованную строку по сети
  • Десериализуйте новый полиморфный вектор на стороне сервера ‹--- Вот где моя проблема

У меня есть класс, производный (и DerivedB, DerivedC и т. Д.), Который является производным от Class Base и класса LotsOfBases, который содержит вектор виртуальной базы.

Хотя я не понимаю, как это могло вызвать проблему - я считаю, что моя проблема заключается в том, что объекты в векторе, поступающие с сервера, находятся в определенном порядке (AAABBCCCCD), и когда они возвращаются, они находятся в случайном порядке и может иметь разное количество производных классов (ABABCDDDA).

Ниже приведены мои неудачные попытки. Используя метод 2 ниже, если мне повезет, я могу отправлять информацию туда и обратно (если порядок классов остается прежним), но когда типы классов меняют порядок, начинают возникать проблемы.

Используемый код и ошибка компиляции / выполнения:

  1. Конечно, компилируется без дополнений, но у меня возникают проблемы с RunTime, поскольку Boost не знает, какой класс какой ... Итак, я попробовал:

  2. ar.template register_type<Derived>() ; - Регистрация класса в "LotsOfBases" .h "функция Serialize и получил следующее при вызове в RunTime: Error @ RunTime: what(): Input Stream Error - Это то, где я добился наибольшего успеха и о чем в основном упоминалось выше.

  3. ar.register_type<static... Но я получаю ошибки компиляции, заявляя, что это функция (видел это еще где на StackOverflow

  4. BOOST_CLASS_EXPORT(Derived) ; В конце файла ".h", который дает n предупреждений для каждого подкласса Base и не может быть скомпилирован. Ошибка: multiple definition of ``boost::archive::detail::extra_detail::init_guid<Derived>::g'

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

  6. BOOST_CLASS_EXPORT_IMPLEMENT(TextQuestion) из Экспорт сериализации классов - то же самое ошибки как 6 iirc.

  7. Приведенные выше примеры без ссылок взяты из моего троллинга через ~ 30 страниц в StackOverflow, которые похожи, но предлагаемые ими решения, похоже, не работают для меня или связаны с Boost Serialization, но несколько неактуальны.

Ниже приводится сокращенная версия моего кода (без изменений, внесенных из других источников):

Код классов

LotsOfBases:

#include "s11n.h" //Import All Serialization Headers In Correct Order
namespace boost { namespace serialization { class access ; } }

class LotsOfBases
{
  public:
   std::vector<Base *> getAllBases() ;
  protected:
    std::vector<Base *> allBases() ;

    friend class boost::serialization::access ;

    template <typename Archive>
    void serialize(Archive& ar, const unsigned int /*version*/)
    {
        ar & allBases ;
    }

} ;

База:

#include "s11n.h" //Import All Serialization Headers In Correct Order
namespace boost { namespace serialization { class access ; } }

class Base
{
  public: 
    Base() ;
    ~Base() ;

    virtual std::string getBaseLocation() ;
  protected:
    std::string baseLocation ;

    friend class boost::serialization::access ;

    template <typename Archive>
    void serialize(Archive& ar, const unsigned int /*version*/)
    {
        ar & baseLocation ;
    }
} ;

Производный

#include "s11n.h" //Import All Serialization Headers In Correct Order
namespace boost { namespace serialization { class access ; } }

class Derived
{
  public:
    Derived() ;

    bool getIsAttackableBase() ;
  private:
    bool isAttackableBase ;

    typedef Base _super;
    friend class boost::serialization::access ;

    template <typename Archive>
    void serialize(Archive& ar, const unsigned int /*version*/)
    {
        ar & boost::serialization::base_object<_super>(*this) ;
        ar & isAttackableBase ;
    }

Я уверен, что это не должно быть так сложно. Итак, я думаю, мой вопрос ... Что я делаю не так? С чего мне начать читать / исследовать сейчас?


person Tom B    schedule 17.07.2013    source источник
comment
BOOST_CLASS_EXPORT больше не может быть указан во включаемом файле. В документации это не отражено! (Честно говоря, boost документации - отстой, а boost :: serialize - отстой). Попробуйте переместить его в файл реализации. Не могли бы вы подробнее рассказать о BOOST_CLASS_EXPORT_KEY / BOOST_CLASS_EXPORT_IMPLEMENT? Что именно вы сделали, а что не сработало?   -  person n. 1.8e9-where's-my-share m.    schedule 17.07.2013
comment
Также я надеюсь, что это не ваш реальный код (без виртуального деструктора, Derived не наследует Base.)   -  person n. 1.8e9-where's-my-share m.    schedule 17.07.2013


Ответы (1)


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

#pragma once
#include <iostream>
#include <vector>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream.hpp>

using namespace std;
class Parent; // Forward declares 
class Child;  // so my classes are in your order

Семья - это ваш LotsOfBases

class Family {

    friend class boost::serialization::access;

public:
    Family() { ; }
    ~Family() { ; }

    vector<Parent*> m_members;
    //////////////////////////////////////////////////////////////////////
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar.template register_type<Child>();
        ar & m_members;
    }
    //////////////////////////////////////////////////////////////////////

};

Родитель - это ваша База

class Parent {

    friend class boost::serialization::access;

public:
    Parent() : m_name("") { ; } 
    Parent(string name) : m_name(name) { ; }
    ~Parent() { ; }

    virtual string GetName() { return m_name; }
private:

    string m_name;

    //////////////////////////////////////////////////////////////////////
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & m_name;
    }
    //////////////////////////////////////////////////////////////////////
};

Дочерний - это ваш Производный

class Child : public Parent {

    friend class boost::serialization::access;

public:
    Child() : Parent(), m_age(0) { ; }
    Child(string name, int id) : Parent(name), m_age(id) { ; }
    ~Child() { ; }
    int m_age;
private:
    //////////////////////////////////////////////////////////////////////
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & boost::serialization::base_object<Parent>(*this);
        ar & m_age;
    }
    //////////////////////////////////////////////////////////////////////
};

Основное (для полноты)

int main() {

    Child *timmy = new Child("Timmy", 4);
    Family JohnsonFamily; 
    JohnsonFamily.m_members.push_back(timmy);

    // serialize object into a std::string
    std::string serial_str;
    boost::iostreams::back_insert_device<std::string> inserter(serial_str);
    boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>> s(inserter);
    boost::archive::binary_oarchive oa(s);

    oa & JohnsonFamily;
    s.flush();

    // read object backout of standard string into new Family object
    boost::iostreams::basic_array_source<char> device(serial_str.data(), serial_str.size());
    boost::iostreams::stream<boost::iostreams::basic_array_source<char> > t(device);
    boost::archive::binary_iarchive ia(t);

    Family FosterFamily;
    ia & FosterFamily;

    auto baseptr = FosterFamily.m_members[0];
    auto child = dynamic_cast<Child*>(baseptr);
    if (child != nullptr) {
        cout << "Derived type infered from serialized base pointer." << endl;
        cout << child->GetName() << " is " << child->m_age << endl;
    }

    cin.get();
    return 0;
}

Я заметил, что ваш Derived на самом деле не наследуется, что, безусловно, вызывает проблемы. Кроме того, ключевым моментом является то, что если у вас есть полиморфный контейнер в классе, вы должны зарегистрировать каждый производный тип в этом классе (а не в базовом классе). См. Мой семейный класс выше.

Надеюсь, это тебе поможет.

person SullX    schedule 29.11.2015