We help IT Professionals succeed at work.

Boost serialization: Polymorphic Archive problem

shootah
shootah asked
on
1,718 Views
Last Modified: 2012-08-13
I have successfully used an example i found for serializing a derived class from a base class pointer and then deserializing back to the base class pointer.  However when i integrate this example into my current project, I am getting a "class cast exception" when deserializing.

The difference in my project vs. the example is the serialization and deserialization happen in different modules.  I thought it was a registration issue but from what I understood, when the Serialize template function is called, the classes are automatically registered.  I have attached the relevant code.

I feel like I'm leaving out some information that boost needs in order to cast the appropriate class to the base class pointer from the archive.

(sorry about the order of the source code, that wasn't the order i submitted?)
//SerializeWrappers cpp file

#include "SerializeWrappers.h"

template<class Archive>
void derived_1::serialize(Archive & ar, const unsigned int file_version) {

        boost::serialization::void_cast_register<derived_1, base_test>(
        static_cast<derived_1 *> (NULL), static_cast<base_test *> (NULL));
}

derived_1::derived_1(){
        cout<<"derived 1";
}
void derived_1::foo(){
        cout<<" constructing derived 1 ";
}
template<class Archive>
void derived_2::serialize(Archive & ar, const unsigned int file_version) {

        boost::serialization::void_cast_register<derived_2, base_test>(
        static_cast<derived_2 *> (NULL), static_cast<base_test *> (NULL));
}

derived_2::derived_2(){
        cout<<" constructing derived 2";
}
void derived_2::foo(){
        cout<<"derived 2"<<endl;
}

BOOST_CLASS_EXPORT_GUID(derived_1,"derived_1");
BOOST_CLASS_EXPORT_GUID(derived_2,"derived_2");

Open in new window

//Serialize Execution CPP file
#include "SerializeExecution.h"

SerializeExecution::SerializeExecution(std::string filename){

  m_ofStream.open(sRecordFileName.c_str(), std::ios::binary);
  oarchive_t* oa = new oarchive_t(m_ofStream);
  m_ar = oa;
}

void SerializeExecution::ProcessData(){
 
  base_test* b = new derived_1();
  cout<<"interaction b";
  (*m_ar) << BOOST_SERIALIZATION_NVP(b);

}

Open in new window

//deserialization execution cpp file
#include "DeserializeExecution"

void DeserializeExecution::ExecuteDeserialization(std::string filename){

   //read recorded HLA data
                std::ifstream ifs (filename.c_str(),ios::binary);
                iarchive_t ia(ifs);  
       
        while (ifs.peek(),!ifs.eof())
        {
               
                base_test* Data;

                try {
                        ia>>BOOST_SERIALIZATION_NVP(Data);//Class Cast Exception called here
                        Data->foo();                       
                }
                catch(boost::archive::archive_exception& ae)
                {
                        stringstream ss;
                        ss<<"Boost exception while reading data:  "<<ae.what();
                        throw CHLALoggerException(CDiagnosticLogfile::FAULT,ss.str(),__FILE__,__LINE__);

                }
                catch(std::exception& exc){
                        stringstream ss;
                        ss<<"std exception while reading data:  "<<exc.what();
                        throw CHLALoggerException(CDiagnosticLogfile::FAULT,ss.str(),__FILE__,__LINE__);
                }
                catch(...){

                        stringstream ss;
                        ss<<"catchall exception while reading data";
                        throw CHLALoggerException(CDiagnosticLogfile::FAULT,ss.str(),__FILE__,__LINE__);
                }
        }//end while

    ifs.close ();

}

Open in new window

// SerializeWrapper.h header file

#include <iostream>
#include "boost/serialization/export.hpp"
#include <boost/serialization/serialization.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

typedef boost::archive::binary_oarchive oarchive_t;
typedef boost::archive::binary_iarchive iarchive_t;

class base_test{
public:
        friend class boost::serialization::access;
        template<class Archive>
        void serialize(Archive & ar, const unsigned int file_version) {
                }


        base_test(){}
        virtual void foo(){cout<<"base"<<endl;}

};

class derived_1 : public base_test{
public:
        friend class boost::serialization::access;

                template<class Archive>
        void serialize(Archive & ar, const unsigned int file_version);
        derived_1();
        void foo();
};

class derived_2 : public base_test{
public:
        friend class boost::serialization::access;

                template<class Archive>
                void serialize(Archive & ar, const unsigned int file_version);
        derived_2();
        void foo();
};

#endif

Open in new window

//deserialize execution module header file
#include "SerializeWrappers.h"

class DeserializeExecution{
public:
 DeserializeExecution(){}
 void ExecuteDeserialization(std::string filename);

}

Open in new window

//serialization execution header file
//
#include "SerializeWrappers.h"

class SerializeExececution{

public:
SerializeExecution(std::string filename);
ProcessData();

private
  std::ofstream m_ofStream;       
  oarchive_t* m_ar;
}

Open in new window

Comment
Watch Question

evilrixSenior Software Engineer (Avast)
CERTIFIED EXPERT

Commented:
You're probably not calling void_cast_register to register your classes (or not calling it in the correct order) before deserialisation. The framework don't know what to deserialise to. When you register it builds a table of super to sub class. When the class is written the table index is written with it. When you deserialised you need to have registered the super/sub relationship exactly as when you serialised. In then performs a lookup in the table to know what type is being restored.

http://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/serialization.html#derivedpointers

"The system "registers" each class in an archive the first time an object of that class it is serialized and assigns a sequential number to it. Next time an object of that class is serialized in that same archive, this number is written in the archive. So every class is identified uniquely within the archive. When the archive is read back in, each new sequence number is re-associated with the class being read. Note that this implies that "registration" has to occur during both save and load so that the class-integer table built on load is identical to the class-integer table built on save. In fact, the key to whole serialization system is that things are always saved and loaded in the same sequence. This includes "registration"."

Author

Commented:
Hi evilrix,
  Sorry to take so long in response.  I had to put this on the backburner and work on it over the weekend.

Anyway, I followed your link and that is actually the example I am using integrated with my project.  I was not however calling the export macro.  I added the macro in my code and I ended up with linker errors pertaining to the type_info.  I've attached the linker errors.  I also tried the explicit registration per the example (ar.template register_type<derived_1>();
)  but the compiler didn't like the "ar.template" syntax.

Any ideas about the linker error?
./Logger/HLALogger.o: In function `extended_type_info_typeid':
/work/boost_1_45_0/include/boost/serialization/extended_type_info_typeid.hpp:89: undefined reference to `typeinfo for derived_1'
/work/boost_1_45_0/include/boost/serialization/extended_type_info_typeid.hpp:89: undefined reference to `typeinfo for derived_2'
./Logger/HLALogger.o: In function `void boost::serialization::access::serialize<boost::archive::binary_iarchive, derived_2>(boost::archive::binary_iarchive&, derived_2&, unsigned int)':
/work/boost_1_45_0/include/boost/serialization/access.hpp:118: undefined reference to `void derived_2::serialize<boost::archive::binary_iarchive>(boost::archive::binary_iarchive&, unsigned int)'
./Logger/HLALogger.o: In function `void boost::serialization::access::serialize<boost::archive::binary_oarchive, derived_2>(boost::archive::binary_oarchive&, derived_2&, unsigned int)':
/work/boost_1_45_0/include/boost/serialization/access.hpp:118: undefined reference to `void derived_2::serialize<boost::archive::binary_oarchive>(boost::archive::binary_oarchive&, unsigned int)'
./Logger/HLALogger.o: In function `void boost::serialization::access::serialize<boost::archive::binary_iarchive, derived_1>(boost::archive::binary_iarchive&, derived_1&, unsigned int)':
/work/boost_1_45_0/include/boost/serialization/access.hpp:118: undefined reference to `void derived_1::serialize<boost::archive::binary_iarchive>(boost::archive::binary_iarchive&, unsigned int)'
./Logger/HLALogger.o: In function `void boost::serialization::access::serialize<boost::archive::binary_oarchive, derived_1>(boost::archive::binary_oarchive&, derived_1&, unsigned int)':
/work/boost_1_45_0/include/boost/serialization/access.hpp:118: undefined reference to `void derived_1::serialize<boost::archive::binary_oarchive>(boost::archive::binary_oarchive&, unsigned int)'
./Logger/HLALogger.o: In function `void boost::serialization::access::construct<derived_2>(derived_2*)':
/work/boost_1_45_0/include/boost/serialization/access.hpp:132: undefined reference to `derived_2::derived_2()'
./Logger/HLALogger.o: In function `void boost::serialization::access::construct<derived_1>(derived_1*)':
/work/boost_1_45_0/include/boost/serialization/access.hpp:132: undefined reference to `derived_1::derived_1()'
collect2: ld returned 1 exit status

Open in new window

evilrixSenior Software Engineer (Avast)
CERTIFIED EXPERT

Commented:
are you linking to boost_serialization?

Author

Commented:
Yes, I am linking to boost_serialization.
Senior Software Engineer (Avast)
CERTIFIED EXPERT
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
I took your advice and created a test project as close to my project structure as possible.  I'm not sure if this bad or good but my test project works.  It seems I cannot recreate my problem in the test project.  I guess from here I will try to make sure what i am doing in the test project i will also do in my main project.  Thanks for the help and advice.
evilrixSenior Software Engineer (Avast)
CERTIFIED EXPERT

Commented:
Ah, well that is actually a result because at least you now have a working example that you can use to check your main project.

I know you've closed up here but do post back if you need any more assistance.

Best of luck.

Author

Commented:
Thanks...and don't listen to what they say about you.  Your not so evil!  XD
evilrixSenior Software Engineer (Avast)
CERTIFIED EXPERT

Commented:
Hahaha :)
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.