boost :: serialization: перегрузка load_construct_data: нет доступного конструктора вообще - PullRequest
3 голосов
/ 13 августа 2011

поэтому я использую библиотеку boost :: serialization и пытаюсь переопределить, как создается класс, поскольку у него нет конструктора по умолчанию.Это продемонстрировано здесь .Мне кажется, что функция берет class* t, а затем устанавливает его, чтобы указать на недавно построенный объект.Если я ошибаюсь, это определенно источник моей ошибки.

Однако, единственный способ создать мой класс - использовать другую функцию create() классов, то есть мне нужно отклониться от кода впример ( это указано в пространстве имен boost :: serialization ): ::new(t)my_class(attribute);

Я попытался просто вызвать функцию create и установить t равным возвращенному указателю, но это некажется, не работает, потому что сразу после load_construct_data function, а в serialization function, данный myClass& не совпадает с тем, что я установил для 't'.

Как мнеделать все, что :: new (t) делает, чтобы объект, созданный с помощью функции create, выполнял сериализацию / другие функции?

Ответы [ 2 ]

2 голосов
/ 13 августа 2011

Упомянутая в вашем вопросе конструкция (new(t) my_class(attribute)) называется "размещение нового".Вот как это работает:

  1. t уже должен указывать на выделенную область памяти (размещение нового не выделяет по умолчанию)
  2. Экземпляр my_classсоздается в этой ячейке памяти.

Однако, поскольку в вашем случае вы не можете использовать конструкторы, использование любой формы new исключено.Но есть альтернатива (своего рода).

Поскольку размещение new в значительной степени просто перезаписывает чанк-память, мы можем использовать обычную функцию, которая делает то же самое с уже созданным объектом.Такой функцией является memcpy:

void * memcpy ( void * destination, const void * source, size_t num );

Все, что memcpy выполняет, выполняет побайтную копию num байтов из памяти, на которую указывает source, в память, на которую указывает destination.

Допустим, вы начали с этого кода в load_construct_data

my_class obj = other_class::create();

Затем мы можем использовать функцию memcpy, чтобы "переместить" значение в objв ссылку на память по t:

memcpy((void*)t, (void*)(&obj), sizeof(obj));

Хотя есть некоторые подробности о том, как это работает с вашим конкретным классом, например, является ли побитовая копия «достаточно хорошей», это лучшийУ меня есть то, что вы спросили.Единственная проблема, которую я вижу, - если деструктор освобождает ресурсы, то копия может стать недействительной.

Чтобы учесть возможные проблемы с уничтожением, вы можете написать свою собственную функцию глубокого копирования:

void deepCopy( my_class * destination, const my_class * source );

, который вы называете вместо memcpy.

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

1 голос
/ 05 мая 2016

В случае отсутствия конструктора по умолчанию использование данных load_construct_data и save_construct фактически позволяет использовать экземпляры shared_ptr. На мой взгляд, нет необходимости возиться с memcpy и необработанными указателями. Таким образом, вы можете просто сделать что-то вроде следующего

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>

#include <memory>

class MyClass {
  public:
    explicit MyClass(std::string const &str) : m_str(str) {}
    MyClass() = delete;
    std::string str() const
    {
        return m_str;
    }
 private:
   std::string m_str;
};

namespace boost { namespace serialization {

    template<class Archive>
    void serialize(Archive &ar,
                   MyClass const & myClass,
                   unsigned int const) 
    {
        auto str = myClass.str();
        ar & str;
    }

    template<class Archive>
    void save_construct_data(Archive &ar,
                             MyClass const * myClass,
                             unsigned int const)
    {
        auto str = myClass->str();
        ar << str;
    }

    template<class Archive>
    void load_construct_data(Archive &ar,
                             MyClass * myClass,
                             unsigned int const)
    {
        std::string archived;
        ar >> archived;
        ::new(myClass)MyClass(MyClass(archived));
    }
}
}

int main(int argc, const char * argv[]) {

    std::shared_ptr<MyClass> myClass(new MyClass("hello!"));
    std::stringstream os;
    ::boost::archive::text_oarchive oa(os);
    oa << myClass;

    std::shared_ptr<MyClass> myClassB;
    std::stringstream is;
    is.str(os.str());
    ::boost::archive::text_iarchive ia(is);
    ia >> myClassB;

    return 0;
}
...