5

Sto provando a serializzare le mie strutture di dati per scriverle su un socket tcp.Errore di serializzazione di una classe astratta con boost

Finora ho scoperto che il mio problema è la serializzazione. Ho anche provato a usare

BOOST_SERIALIZATION_ASSUME_ABSTRACT(T) 

ma non riesco a trovare alcun esempio di lavoro simile al mio programma e come implementarlo correttamente.

Ecco alcuni dei link che ho visitato:

mie strutture di dati sono un po 'più complicato, allora questo, ma supponiamo che ho la seguente struttura

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

I metodi virtuali sono definiti qui.

MoveNormal.cpp

#include "MoveNormal.h" 

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

mio main.cpp si presenta così:

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

Ma quando ho eseguito il programma ottengo il seguente errore:

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

I' m utilizzando VS2010 e Boost 1.48.0.

+0

dichiarare un operatore sovraccarico << come un amico della classe, quindi implementarlo, Considerando che la struttura dati è costituita da un valore int questo dovrebbe essere completamente banale fare. Se hai bisogno di trasmetterlo su un socket, semplicemente reinterpret_cast l'int a char * e invialo sul socket;) – johnathon

+0

Il fatto è che la mia struttura dati non ha solo un int. L'esempio sopra è una struttura semplice creata solo per questo caso. Considera che all'interno della mia struttura ho dei riferimenti ad altre classi e ai contenitori di stl. Finora penso di aver capito come farlo funzionare. Lo sto solo testando nel mio progetto e posterò la soluzione qui il prima possibile. – ealves

risposta

7

Questo è un po 'strano, ma ho intenzione di rispondere alla mia domanda. Ho appena capito come far funzionare il mio esempio sopra.

Ecco la soluzione. Ogni volta che abbiamo bisogno di serializzare una classe che eredita gli attributi da un'altra classe abbiamo bisogno di usare la macro:

BOOST_CLASS_EXPORT(T) 

Secondo il 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.

Quindi, nel mio caso, il mio file main.cpp è ora:

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

Assicurati di includere tutti gli archivi boost necessari prima di utilizzare la MACRO di esportazione.

Per completare il mio progetto oltre alla serializzazione, è necessario scriverli in un socket TCP utilizzando boost :: asio.

Quindi cerchiamo di pensare che ho un colpo di testa del collegamento come this one e che ora ho un'altra classe chiamata MoveJump definito nel mio 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); 
    } 
}; 

Ora per serializzare queste strutture il mio aspetto principale come questo

Il trucco è registrare le classi che verranno serializzate quando avremo il puntatore alla classe base.

Se all'interno del mio Move.h ho più puntatori ad altre classi base, cosa che faccio nel mio progetto, abbiamo bisogno di includere nel main tutte le intestazioni e registrare tutte le possibili classi che espandono la classe base.

Spero che questo aiuti qualcuno che potrebbe avere problemi simili in futuro.

Sentiti libero di presentare nuove soluzioni possibili.

Grazie

0

parlare generale, si può semplicemente utilizzare BOOST_CLASS_EXPORT per registrare tutte le classi, oppure è possibile utilizzare BOOST_SERIALIZATION_ASSUME_ABSTRACT per la classe super, e utilizzare la funzione di membro register_type di "archivio" insieme. vedi: How to serialize derived template classes with Boost.serialize? per i dettagli. (scusate il mio povero inglese :))

Problemi correlati