Re: [Boost-users] [Serialization] Problem serializing via baseclassptr
Robert,
I've created a simple test as you suggested. The problem is that the test does not even build (in oserializer.hpp, there are 2 conditions for this to happen but none seems to match my test..). Here's what the compiler gives me:
C:/Boost/include/boost-1_33_1/boost/archive/detail/oserializer.hpp: In function `void boost::archive::save(Archive&, T&) [with Archive = boost::archive::text_oarchive, T = A]':
C:/Boost/include/boost-1_33_1/boost/archive/basic_text_oarchive.hpp:78: instantiated from `void boost::archive::basic_text_oarchive<Archive>::save_override(T&, int) [with T = A, Archive = boost::archive::text_oarchive]'
C:/Boost/include/boost-1_33_1/boost/archive/detail/interface_oarchive.hpp:78: instantiated from `Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = A, Archive = boost::archive::text_oarchive]'
../main.cpp:90: instantiated from here
C:/Boost/include/boost-1_33_1/boost/archive/detail/oserializer.hpp:567: error: incomplete type `boost::STATIC_ASSERTION_FAILURE<false>' does not have member `value'
#include <iostream>
#include <fstream>
#include
Hmm - looks like it should work to me.
I would try the following:
a) make a tiny test - a main which which does nothing but tests the serialization. This you can ship to us in necessary. b) For now - remove all the BOOST_CLASS_TRACKING macros. It shouldn't make a difference but let's start simple. c) You'll have to add BOOST_CLASS_EXPORT for SomeData d) double check that everything is in the same namespace. e) try removing the friend class boost::serialization::access; from the base class. NonVolatileData::serialize(..) should never be called by the serialization library in this case - so if this traps during >compile, it will show a chain of "compile time calls". By looking at this chain one can see where things went wrong. Unfortunately this requires looking at the header source code - oh well. f) double check that the test corresponding to your example builds and runs in your environment. If that passes, but yours does not, try modifying the test bit by bit by commenting out the code that is there and replacing it with your own code. If you finish this and the test still works - then just remove all the commented code and you'll be done.
Robert Ramey
Guy Létourneau wrote:
Robert, I've tried to include your changes but it doesn't solve the problem. I had to add the following line: BOOST_IS_ABSTRACT(NonVolatileData) for the program to compile. I agree with you, to have an abstract class is what is needed in that case as the NonVolatileData class is not intended to do something useful except for allowing my data storage layer to be generic. However, abstract or not, I still have the same problem: when serializing my SomeData object through a pointer to the NonVolatileData, only the data of the parent class gets serialized. Anything else you want me to try?
Thanks, Guy
Try making the base class polymorphic - that it define at least one abstract function. See my changes below. This will have the beneficial effect of inhibiting anyone from creating an instance of your base class directly. Robert Ramey
Guy Létourneau wrote:
Hello,
I need to develop a generic data storage layer. Its job is to handle the serialization of all objects that need to be persistent in my system and handle management of archives, backups and restores and so forth. The most important point is that it must stay generic, i.e. have no knowledge of the type of objects being passed by other modules in the system. Because of this, I define a base class NonVolatileData from which all data classes in the system will derive:
/////////////////////////////////////////////////////////////////////// // Base class class NonVolatileData { friend class boost::serialization::access;
public:
NonVolatileData(){ i = 1; }; virtual ~NonVolatileData() = 0; // Note - pure virtual function make class abstract-
protected:
virtual void Dummy() =0; // Note - pure virtual function make class abstract- ;
int i; template <class Archive> void serialize( Archive& ar, const unsigned int version ) { ar & i; } }; BOOST_CLASS_TRACKING(NonVolatileData, boost::serialization::track_never)
class SomeData: public NonVolatileData { friend class boost::serialization::access;
public:
SomeData () { };
~SomeData () { };
void SetValue( std::string& Address ) { this->Address = Address; }
void Dummy() { }
private:
template <class Archive> void serialize( Archive& ar, const unsigned int version ) { ar &
boost::serialization::base_object<NonVolatileData>(*this); ar& Address; }
std::string Address; }; BOOST_CLASS_TRACKING(SomeData, boost::serialization::track_never) /////////////////////////////////////////////////////////////////
My data storage interface will take a ptr to the base class i.e. Save(NonVolatileData* data) so the serialization will be performed through a ptr to the base class. I've read the documentation multiple times and I'm still unable to make that work correctly. When a do a save, only the base class is serialized even though the base class is polymorphic. I've tried using the BOOST_CLASS_EXPORT_GUID macro the force a registration of my derived class without success. I've also checked the example from demo.cpp. It uses the direct call to register_type() but in my case, I don't want to change the code everytime a new class is defined in the system so I went with option 2 (the macro). There's probably a subtle detail I do not do correctly (polite way of saying I'm missing something :-)).
Thanks for your help,
Guy Letourneau =
Three show stopping problems in this code: a) A doesn't have serialize method even though such a method is invoked by base object. see: http://www.boost.org/libs/serialization/doc/serialization.html b) saving a non-const object - see rationale section c) Main show stopper:
int main() { // Create a B object B* Child = new B;
// Set some data std::string Data = "test"; Child->SetValue( Data );
// Assign it to a A ptr // const A* Parent = Child; // ****** note new const - see rationale
// create and open a character archive for output std::ofstream ofs( "filename" );
// save data to archive { try { boost::archive::text_oarchive oa( ofs ); // write class instance to archive // *** big problem here. Dereferecing pointer to A yields a ref // *** to an A - regardless that ptr was a B. What you really want is: oa << Parent; // *** let serialization handle dererencing // *** instead of: //oa << *Parent; } catch( boost::archive::archive_exception& e ) { std::cout << "Save failed! : " << e.what(); std::cout.flush();
return false; } catch( ... ) { std::cerr << "Unknown Exception " << std::endl;
return false; }
// archive and stream closed when destructors are called }
delete Child; }
participants (2)
-
Guy Létourneau
-
Robert Ramey