2010-08-03 18 views
12

Estoy tratando de serializar un puntero a una clase polimórfica Shape. Entonces necesito usar el BOOST_CLASS_EXPORT macro para definir un GUID para cada subclase. El problema: ¿dónde ponerlo?¿Dónde poner BOOST_CLASS_EXPORT para impulsar :: serialización?

Te voy a enseñar un caso de prueba mínima en primer lugar:

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; 
} 

En gcc, puedo compilar estos con

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

Aquí, export.cpp puede parecer un poco tonto. En mi situación actual, contiene una clase adjunta que usa el modismo PIMPL, y trata de serializar su implementación (polimórfica) Shape. El punto importante es: el BOOST_CLASS_EXPORT podría estar en un diferente archivo de objeto que el código que invoca la serialización.

Así que aquí está el problema: dónde usar BOOST_CLASS_EXPORT? Tengo tres opciones, que se pueden habilitar usando las macros EXPORT_IN_XXX.

  1. EXPORT_IN_MAIN funciona, pero no es lo que quiero. El código que invoca la serialización no debería necesitar conocer los detalles de implementación de la clase PIMPL.

  2. EXPORT_IN_OBJECT compila, pero no funciona: el resultado es una boost::archive::archive_exception con el mensaje unregistered void cast. De acuerdo con documentation, esto debería resolverse serializando clases base usando boost::serialization::base_object, como lo hice, pero no ayuda.

  3. EXPORT_IN_HEADER ni siquiera se compila. El macro BOOST_CLASS_EXPORT se expande a una especialización de plantilla (que nos gustaría que estuviese en el archivo de encabezado), pero también a la definición de un miembro estático en el mismo. Entonces recibo un error del enlazador sobre multiple definition of 'boost::archive::detail::init_guid<Rect>::guid_initializer'.

Si es importante, estoy usando g ++ 4.4.3 y Boost 1.40.

+0

¿Ha resuelto este problema? He encontrado este problema yo mismo, obteniendo una excepción de clase no registrada en tiempo de ejecución o errores 'boost :: archive :: detail :: init_guid :: guid_initializer' en tiempo de compilación. Estoy bastante perplejo, así que si lo has entendido desde que hice esta pregunta, ¡realmente apreciaría que compartieras! ¡Gracias! – bguiz

+0

@bguiz: Realmente no lo resolvió, no. Ver mi respuesta a continuación. – Thomas

Respuesta

5

me acabó poniendo todo el código de serialización en una cabecera s11n.h que se incluye desde el archivo CPP que invoca la serialización. Básicamente, el escenario EXPORT_IN_MAIN esbozado arriba, pero con las invocaciones de macro BOOST_CLASS_EXPORT en un archivo diferente.

Esto solo funciona siempre que solo una unidad de compilación incluya s11n.h, por supuesto, así que aunque funciona por ahora, no es una solución real ...

+1

+1 para s11n - ¡nunca antes se había visto! – bguiz

+0

Por desgracia, esto no funcionó para mí, lo que terminé haciendo fue utilizar 'Archive :: register_type (static_cast (NULL))' dentro del método de serialización de la clase central que se está serializando. Esto funcionó para mí, h/w No creo que sea el mismo escenario que encontraste ~ – bguiz

+0

@bguiz: Bueno, eso sería un argumento * en contra del * uso de la abreviatura, supongo ...;) Pero yo Soy el único que mantiene este código, así que no es un problema para mí. Guarda cargas de tipeo – Thomas

2

Puede usar EXPORT_IN_OBJECT pero el archivo que contiene BOOST_CLASS_EXPORT también debe incluir todos los archivos hpp de archivo que planean usar.

Esto se debe a que la macro BOOST_CLASS_EXPORT registra la información de tipo derivado, que cada archivo comprimido que piensa que va a utilizar (de forma implícita determinada en base a la cual los archivos que haya incluido.)

En su ejemplo, utilizar EXPORT_IN_OBJECT sino también añadir #include a export.cpp.

En nuestro código, creamos archives.hpp que contiene los archivos que usamos y los incluimos donde necesitamos usar BOOST_CLASS_EXPORT. (De esta forma tenemos una única lista oficial de archivos.)

El inconveniente es que tenemos que reconstruir todo cuando decidimos usar un nuevo tipo de archivo, pero encontramos que es mucho más fácil de usar que el soporte de archivos polimórficos.

8

Exporting Class Serialization de los docs Boost.Serialization (1.44.0) afirma lo siguiente:


BOOST_CLASS_EXPORT en el mismo módulo fuente que incluye cualquiera de los encabezados de clase archivo instanciará código [ ...]

Tenga en cuenta que la implementación de esta funcionalidad requiere que BOOST_CLASS_EXPORT ma cro aparece después y la inclusión de cualquier archivo encabezados de clase cuyo código va a ser instanciado. Por lo tanto, el código que utiliza BOOST_CLASS_EXPORT se verá como lo siguiente:

#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 

[...] Incluyendo BOOST_CLASS_EXPORT en la "a.hpp" de cabecera en sí como cabría ver con otra serialización los rasgos harán que sea difícil o imposible seguir la regla anterior con respecto a inclusión de encabezados de archivo antes de se invoca. Puede dirigirse a este usando BOOST_CLASS_EXPORT_KEY en las declaraciones de encabezado y BOOST_CLASS_EXPORT_IMPLEMENT en el archivo de definición de clase .


+0

He puesto BOOST_CLASS_EXPORT_KEY en mi encabezado y BOOST_CLASS_EXPORT_IMPLEMENT en mi archivo de implementación. Construyo una biblioteca a partir de ellos, y luego, cuando trato de serializar el objeto en un ejecutable que se vincula a la biblioteca, el serializador no sabe sobre el tipo. Vea este ejemplo: http://chat.stackoverflow.com/transcript/message/28926778#28926778 –

+0

@DavidDoria - lo siento, no puedo ayudarlo allí. Mucho tiempo después de hacer cualquier cosa con Boost.Ser –

0

puede utilizar y BOOST_CLASS_EXPORT_GUID única() para cada .cpp y añadirlo sólo en el .cpp. no el .h

0

Este problema me volvió loco hasta que me di cuenta de que mi clase base no era polimórfica. En otras palabras, nunca usó la palabra clave "virtual" en ninguna parte. Porque no necesitaba comportamiento polimórfico.

Así es como me fijo:

  1. acabo abofeteó la palabra clave "virtual" en algún método al azar en mi clase base.
  2. En el archivo .cpp de mi clase derivada, que añade el texto siguiente:

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

Esto es todo lo que tenía que hacer.

+0

No es una solución. Una solución fea en el mejor de los casos. – Berkus