5

Estoy intentando serializar mis estructuras de datos para escribirlas en un socket tcp.Error al serializar una clase abstracta con refuerzo

Hasta ahora encontré que mi problema es la serialización. Incluso traté de usar

BOOST_SERIALIZATION_ASSUME_ABSTRACT(T) 

pero no encuentro ningún ejemplo de trabajo similar a mi programa y cómo implementarlo correctamente.

Éstos son algunos de los enlaces que he visitado:

Mis estructuras de datos son un poco más complicado que éste, pero vamos a suponer que tengo la siguiente estructura

Coordinate.h

#include <boost\archive\text_iarchive.hpp> 
#include <boost\archive\text_oarchive.hpp> 

class Coordinate { 
public: 
    Coordinate() {} 
    Coordinate(int c) : c(c) {} 
    int get(void) { return c; } 
    std::string toString(void); 
private: 
    int c; 
    friend class boost::serialization::access; 
    template<typename Archive> 
    void serialize(Archive &ar, const unsigned int version) { 
     ar & this->c; 
    } 
}; 

Move.h

class Coordinate; 

#include "Coordinate.h" 

#include <boost\archive\text_iarchive.hpp> 
#include <boost\archive\text_oarchive.hpp> 

class Move { 
public: 
    Move() {} 
    ~Move() {} 
    Coordinate* getCoordinate(void) {return this->destination; } 
    virtual bool isJump(void) = 0; 
protected: 
    Coordinate *destination; 
private: 
    friend class boost::serialization::access; 
    template<typename Archive> 
    void serialize(Archive &ar, const unsigned int version) { 
     ar & this->destination; 
    } 
}; 

MoveNormal.h

class Coordinate; 

#include "Move.h" 
#include "Coordinate.h" 

#include <boost\archive\text_iarchive.hpp> 
#include <boost\archive\text_oarchive.hpp> 

class MoveNormal : public Move { 
public: 
    MoveNormal() {} 
    MoveNormal(Coordinate *destination) { this->destination = destination; } 
    ~MoveNormal() {} 
    virtual bool isJump(void); 
private: 
    friend class boost::serialization::access; 
    template<typename Archive> 
    void serialize(Archive &ar, const unsigned int version) { 
     ar & boost::serialization::base_object<Move>(*this); 
    } 
}; 

Se definen los métodos virtuales en aquí.

MoveNormal.cpp

#include "MoveNormal.h" 

bool MoveNormal::isJump(void) { 
    return false; 
} 

Mi main.cpp se ve así:

#include "Coordinate.h" 
#include "Move.h" 
#include "MoveNormal.h" 

#include <fstream> 

#include <boost\archive\text_iarchive.hpp> 
#include <boost\archive\text_oarchive.hpp> 

int main(int argc, char *argv[]) { 
    Coordinate *c = new Coordinate(10); 
    // This runs OK 
    /* 
    { 
     std::ofstream ofs("f.txt"); 
     boost::archive::text_oarchive oa(ofs); 
     oa << c; 
    } 
    Coordinate *d; 
    { 
     std::ifstream ifs("f.txt"); 
     boost::archive::text_iarchive ia(ifs); 
     ia >> d; 
    } 
    std::cout << "c.get(): " << c->get() << std::endl; 
    std::cout << "d.get(): " << d->get() << std::endl; 
    */ 

    // This is where I get my error 
    Move *m = new MoveNormal(c); 
    { 
     std::ofstream ofs("f.txt"); 
     boost::archive::text_oarchive oa(ofs); 
     oa << m; // Line where the error occurs 
    } 
    return 0; 
} 

Pero cuando ejecuto el programa me sale el siguiente error:

Unhandled exception at 0x76dbb9bc in Test.exe: Microsoft C++ exception: boost::archive::archive_exception at memory location 0x001df078..

I' m utilizando VS2010 y Boost 1.48.0.

+0

declaro un operador sobrecargado << como un amigo de la clase, luego impleméntelo, Considerando que su estructura de datos consiste en solo un valor int, esto debería ser completamente trivial que hacer. Si necesita transmitir esto sobre un socket, simplemente reinterprete_cast el int a char * y envíelo a través del socket;) – johnathon

+0

El hecho es que mi estructura de datos no tiene solo un int. El ejemplo anterior es una estructura simple creada solo para este caso. Considere que dentro de mi estructura tengo punteros a otras clases y contenedores stl. Hasta ahora, creo que he descubierto cómo hacerlo funcionar. Solo lo estoy probando en mi proyecto y publicaré la solución aquí tan pronto como pueda. – ealves

Respuesta

7

Esto es un poco extraño, pero voy a responder mi propia pregunta. Acabo de descubrir cómo hacer que mi ejemplo anterior funcione.

Aquí va la solución. Cada vez que necesitamos para serializar una clase que hereda los atributos de otra clase que tenemos que utilizar la macro:

BOOST_CLASS_EXPORT(T) 

De acuerdo con la boost serialization doc

BOOST_CLASS_EXPORT in the same source module that includes any of the archive class headers will instantiate code required to serialize polymorphic pointers of the indicated type to the all those archive classes. If no archive class headers are included, then no code will be instantiated.

Note that the implemenation of this functionality requires that the BOOST_CLASS_EXPORT macro appear after and the inclusion of any archive class headers for which code is to be instantiated.

Así que en mi caso mi archivo main.cpp es ahora:

#include <fstream> 

#include <boost\archive\text_iarchive.hpp> 
#include <boost\archive\text_oarchive.hpp> 
#include <boost\serialization\export.hpp> 

#include "Coordinate.h" 
#include "Move.h" 
#include "MoveNormal.h" 
BOOST_CLASS_EXPORT(MoveNormal) 

int main(int argc, char *argv[]) { 
    Coordinate *c = new Coordinate(150); 
    Move *m = new MoveNormal(c); 
    std::cout << "m.getDestination().get(): " << m->getDestination()->get() << std::endl; 
    { 
     std::ofstream ofs("f.txt"); 
     boost::archive::text_oarchive oa(ofs); 
     oa << m; 
    } 

    Move *n; 
    { 
     std::ifstream ifs("f.txt"); 
     boost::archive::text_iarchive ia(ifs); 
     ia >> n; 
    } 
    std::cout << "n.getDestination().get(): " << n->getDestination()->get() << std::endl; 
    return 0; 
} 

Solo asegúrese de incluir todos los archivos de impulso que necesite antes de usar el MACRO de exportación.

Para terminar mi proyecto además de la serialización, necesito escribirlos en un socket tcp usando boost :: asio.

Así que vamos a asumir que tengo una cabecera de la conexión como this one y que ahora tengo otra clase llamada MoveJump definido en mi MoveJump.h

#include <boost\archive\text_iarchive.hpp> 
#include <boost\archive\text_oarchive.hpp> 

#include "Coordinate.h" 
#include "Move.h" 

class MoveJump : public Move { 
public: 
    MoveJump() {} 
    MoveJump(Coordinate *c) { this->destinatio = c; } 
    ~MoveJump() {} 
    virtual bool isJump(void); 
private: 
    friend class boost::serialization::access; 
    template<typename Archive> 
    void serializize(Archive &ar, const unsigned int version) { 
     ar & boost::serialization::base_object<Move>(*this); 
    } 
}; 

Ahora serializar estas estructuras mi mirada principal como esto

El truco es registrar las clases que se serializarán cuando tengamos el puntero a la clase base.

Si dentro de mi Move.h tengo más sugerencias para otras clases base, lo cual hago en mi proyecto, tenemos que incluir en general todos los encabezados y registrar todas las clases posibles que amplíen la clase base.

Espero que esto ayude a alguien que pueda tener problemas similares en el futuro.

No dude en presentar nuevas soluciones posibles.

Gracias

0

general de habla, puede simplemente usar BOOST_CLASS_EXPORT para registrar todas las clases, o puede utilizar BOOST_SERIALIZATION_ASSUME_ABSTRACT para la superclase, y utilizar la función miembro register_type de "archivo" juntos. ver: How to serialize derived template classes with Boost.serialize? para detalles. (perdón por mi inglés pobre :))

Cuestiones relacionadas