2010-08-03 1 views
12

Я пытаюсь сериализовать указатель на полиморфный класс Shape. Поэтому мне нужно использовать BOOST_CLASS_EXPORT macro для определения GUID для каждого подкласса. Проблема: где это сказать?Где разместить BOOST_CLASS_EXPORT для boost :: serialization?

Позвольте мне показать минимальный тестовый пример первый:

shapes.hpp

#include <boost/serialization/access.hpp> 
#include <boost/serialization/base_object.hpp> 
#include <boost/serialization/export.hpp> 

class Shape { 
    friend class boost::serialization::access; 

    template<typename Archive> 
    void serialize(Archive &ar, unsigned int const version) { 
     // nothing to do 
    } 

    public: 
     virtual ~Shape() { } 
}; 

class Rect : public Shape { 
    friend class boost::serialization::access; 

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

    public: 
     virtual ~Rect() { } 
}; 

#ifdef EXPORT_IN_HEADER 
    BOOST_CLASS_EXPORT(Rect) 
#endif 

export.cpp

#include <boost/serialization/export.hpp> 
#include "shapes.hpp" 

#ifdef EXPORT_IN_OBJECT 
    BOOST_CLASS_EXPORT(Rect) 
#endif 

main.cpp

#include <iostream> 
#include <boost/archive/text_oarchive.hpp> 
#include <boost/serialization/export.hpp> 
#include "shapes.hpp" 

#ifdef EXPORT_IN_MAIN 
    BOOST_CLASS_EXPORT(Rect) 
#endif 

int main() { 
    Shape *shape = new Rect(); 
    boost::archive::text_oarchive ar(std::cout); 
    ar << shape; 
} 

На НКУ, компилировать их с

g++ -omain main.cpp export.cpp -Wl,-Bstatic -lboost_serialization-mt -Wl,-Bdynamic -DEXPORT_IN_XXX 

Здесь export.cpp может выглядеть немного глупо. В моей реальной ситуации он содержит охватывающий класс, который использует идиому PIMPL, и пытается сериализовать его (полиморфную) реализацию Shape. Важным моментом является то, что BOOST_CLASS_EXPORT может быть в объектном файле разных, чем код, вызывающий сериализацию.

Итак, вот в чем проблема: где использовать BOOST_CLASS_EXPORT? У меня есть три варианта, которые можно включить с помощью макросов EXPORT_IN_XXX.

  1. EXPORT_IN_MAIN Работы, но это не то, что я хочу. Код, вызывающий сериализацию, не должен знать о деталях реализации класса PIMPL.

  2. EXPORT_IN_OBJECT компилируется, но не работает: в результате получается сообщение boost::archive::archive_exception с сообщением unregistered void cast. Согласно documentation, это должно быть разрешено путем сериализации базовых классов с использованием boost::serialization::base_object, как и я, но это не помогает.

  3. EXPORT_IN_HEADER даже не компилируется. Макрос BOOST_CLASS_EXPORT расширяется до специализации шаблона (который мы хотели бы быть в файле заголовка), но также и для определения статического члена в нем. Поэтому я получаю ошибку компоновщика около multiple definition of 'boost::archive::detail::init_guid<Rect>::guid_initializer'.

Если это имеет значение, я использую g ++ 4.4.3 и Boost 1.40.

+0

Вы решили эту проблему? Я сам столкнулся с этой проблемой, либо получив незарегистрированное исключение класса во время выполнения, либо 'boost :: archive :: detail :: init_guid :: guid_initializer' ошибки во время компиляции. Я очень взволнован, поэтому, если вы поняли это, задав этот вопрос, я бы очень признателен, если бы вы поделились! Благодаря! – bguiz

+0

@bguiz: Не совсем решил, нет. См. Мой ответ ниже. – Thomas

ответ

5

я в конечном итоге положить весь код сериализации в заголовке s11n.h, который включается из файла CPP, который вызывает сериализации. По сути, сценарий EXPORT_IN_MAIN, который я набросал выше, но с макрокомандами BOOST_CLASS_EXPORT в другом файле.

Это работает только до тех пор, пока только один блок компиляции включает в себя s11n.h, хотя, хотя он работает и сейчас, это не настоящее решение ...

+1

+1 для s11n - никогда не видел этого раньше! – bguiz

+0

Увы, это не сработало для меня - то, что я сделал, это использовать «Archive :: register_type» (static_cast (NULL)) 'в рамках метода сериализации центрального класса, который был серилизован. Это сработало для меня, ч/б. Я не думаю, что это тот же самый сценарий, с которым вы столкнулись. ~ – bguiz

+0

@bguiz: Ну, это будет аргумент * против * использования аббревиатуры, я думаю ...;) Но я «Единственный, кто поддерживает этот код, так что это не проблема для меня. Сохраняет множество наборов. – Thomas

2

Вы можете использовать EXPORT_IN_OBJECT, но файл, содержащий BOOST_CLASS_EXPORT, должен также содержать все файлы hpp архива, которые планируют использовать.

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

В вашем примере, используйте EXPORT_IN_OBJECT, но и добавить #include to export.cpp.

В нашем коде мы создали archives.hpp, который содержит архивы, которые мы используем, и включаем их там, где нам нужно использовать BOOST_CLASS_EXPORT. (Таким образом, у нас есть один официальный список архивов.)

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

8

Exporting Class Serialization из Boost.Serialization документации (1.44.0) говорится следующее:


BOOST_CLASS_EXPORT в том же модуле источника, который включает в себя любой из заголовков класса архива будет экземпляром кода [ ...]

Обратите внимание, что для реализации этой функциональности требуется, чтобы BOOST_CLASS_EXPORT ma cro появляются после и включение любого архива заголовки классов, для которых код должен быть экземпляров. Таким образом, код, который использует BOOST_CLASS_EXPORT будет выглядеть следующее:

#include <boost/archive/text_oarchive.hpp> 
#include <boost/archive/text_oarchive.hpp> 
... // other archives 

#include "a.hpp" // header declaration for class a 
BOOST_CLASS_EXPORT(a) 
... // other class headers and exports 

[...] Включая BOOST_CLASS_EXPORT в «a.hpp» заголовка себя как один бы делать с другими сериализации характеристики затрудняют или невозможны , чтобы следовать приведенному выше правилу относительно включения заголовков архива до BOOST_CLASS_EXPORT. Это лучше всего решить, используя BOOST_CLASS_EXPORT_KEY в заголовке деклараций и BOOST_CLASS_EXPORT_IMPLEMENT в файле определения класса .


+0

Я поместил BOOST_CLASS_EXPORT_KEY в свой заголовок и BOOST_CLASS_EXPORT_IMPLEMENT в мой файл реализации. Я строю библиотеку из них, а затем, когда я пытаюсь сериализовать объект в исполняемом файле, который ссылается на библиотеку, сериализатор не знает о типе. См. Этот пример: http://chat.stackoverflow.com/transcript/message/28926778#28926778 –

+0

@DavidDoria - извините, не могу вам помочь. Долгое время с тех пор что-то делал с Boost.Ser –

0

вы можете использовать и уникальный BOOST_CLASS_EXPORT_GUID() для каждого .cpp и добавить его только в .cpp. а не .h

0

Эта проблема сводила меня с ума, пока я не понял, что мой базовый класс не был полиморфным. Другими словами, он никогда не использовал ключевое слово «virtual» в любом месте. Потому что мне не нужно полиморфное поведение.

Вот как я установил его:

  1. Я просто ударил ключевое слово «виртуальный» на какой-то случайный метод в моем базовом классе.
  2. В файле .cpp мой производный класс, я добавил следующее:

    #include <boost/serialization/export.hpp> 
    BOOST_CLASS_EXPORT(testnamespace::derivedclass) 
    

Это все, что я должен был сделать.

+0

Это не проблема. Ужасный обходной путь в лучшем случае. – Berkus

 Смежные вопросы

  • Нет связанных вопросов^_^