Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1409
  • Last Modified:

Boost serialization: Polymorphic Archive problem

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

0
shootah
Asked:
shootah
  • 5
  • 4
1 Solution
 
evilrixSenior Software Engineer (Avast)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"."
0
 
shootahAuthor 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

0
 
evilrixSenior Software Engineer (Avast)Commented:
are you linking to boost_serialization?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
shootahAuthor Commented:
Yes, I am linking to boost_serialization.
0
 
evilrixSenior Software Engineer (Avast)Commented:
Looking again at the linker errors (sorry, it was late last night and I was tired) it seems the linker is failing to locate derived_1 and derived_2.

What I often do in these situations is try and recreate the issue in a small test project to remove all the distractions of the unrelated code. Can you give that a go and if that still sheds no light post the complete project (of the small test app) here so that I can re-create it my end and I'll take a look.

0
 
shootahAuthor 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.
0
 
evilrixSenior Software Engineer (Avast)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.
0
 
shootahAuthor Commented:
Thanks...and don't listen to what they say about you.  Your not so evil!  XD
0
 
evilrixSenior Software Engineer (Avast)Commented:
Hahaha :)
0

Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now