While coding I always try to learn new ways of writing old things. There are many many libraries out there for C++ all work in different ways, but the library I fell in love with is Boost. Ignoring the massive extension to the STL basic classes it bundles up matrix, graph, system functionality. But what beats all of that mainly because I write it to often is the ever allusive save and load functionality you have to write for all classes. Serialization is one of the things I really miss from my old C# writing days. So here goes a few examples of how to make serialization work!
In C++ there is no reflector so sadly we have to tell the compiler what to save. So an example class
1 class NodeDescriptor{ 2 public: 3 NodeDescriptor() {} ; 4 NodeDescriptor(int offset): 5 Offset(offset){} ; 6 ~NodeDescriptor() {} ; 7 int Offset; 8 private: 9 };
Very very basic, one public variable this is an internal of another object so is reasonable to allow a public property style access. So what we want to do is to do is allow Boost access to save out the variables.
1 class NodeDescriptor{ 2 public: 3 NodeDescriptor() {} ; 4 NodeDescriptor(int offset): 5 Offset(offset){} ; 6 ~NodeDescriptor() {} ; 7 int Offset; 8 private: 9 // Serialization Settings 10 friend class boost::serialization::access; 11 friend std::ostream & operator<<(std::ostream &os, const MotionGraphDesc &mgd); 12 template<class Archive> 13 void serialize(Archive & ar, const unsigned int /* file_version */) 14 { 15 ar & BOOST_SERIALIZATION_NVP(Offset); 16 } 17 };
So what we have added is allowing boost access via a friend operator. Then adding a class for serialize the data, unfortunately you have to define the data of which there is many ways todo, above is an example of the xml way, what this does is create a xml tag called Offset where it stores the value of Offset. Alternatively say we had a private member _offset, it wouldn’t be visually nice to read the xml so we can customise the name of the tag.
1 void serialize(Archive & ar, const unsigned int /* file_version */) 2 { 3 ar & boost::serialization::make_nvp("Offset",_offset); 4 }
This is actually what the BOOST_SERIALIZATION_NVP macro roles out into but BOOST_SERIALIZATION_NVP is slightly more convenient in a large amount of cases. So now the question is how do we save? Well if you add in a couple of methods to your class description for Load, Save you get something like this, to note I have defined an enum that will come in to play with the read write functions.
1 bool NodeDescriptor::Load(const char* path,SerializeAsType t){ 2 std::ifstream f(path); 3 if (f.is_open()){ 4 Read(f,t); 5 }else 6 return false; 7 } 8 9 bool NodeDescriptor::Save(const char* path,SerializeAsType t){ 10 std::ofstream f(path); 11 if (f.is_open()){ 12 Write(f,t); 13 }else 14 return false; 15 }
Now we define the read write:
1 bool NodeDescriptor::Read(std::istream& str,SerializeAsType t){ 2 switch(t){ 3 case XmlArc: 4 { 5 boost::archive::xml_iarchive ia(str); 6 ia >> boost::serialization::make_nvp("NodeDescriptor",(*this)); 7 } 8 break; 9 case TextArc: 10 { 11 boost::archive::text_iarchive ia(str); 12 ia >> *this; 13 } 14 break; 15 case BinaryArc: 16 { 17 boost::archive::binary_iarchive ia(str); 18 ia >> *this; 19 } 20 break; 21 } 22 return true; 23 } 24 25 bool NodeDescriptor::Write(std::ostream& str,SerializeAsType t){ 26 switch(t){ 27 case XmlArc: 28 { 29 boost::archive::xml_oarchive oa(str); 30 oa << boost::serialization::make_nvp("NodeDescriptor",(*this)); 31 } 32 break; 33 case TextArc: 34 { 35 boost::archive::text_oarchive oa(str); 36 oa << (*this); 37 } 38 break; 39 case BinaryArc: 40 { 41 boost::archive::binary_oarchive oa(str); 42 oa << (*this); 43 } 44 break; 45 } 46 return true; 47 }
How easy is that? Most of the space is taken up by making it more compatible allowing the save and load of XML, Text and Binary archives. One thing to note thought is that this is for the purpose of serialization not really a property config file. The other thing to consider is this is a lazy coder solution, it isn’t fast so don't create massive xml files or they will take a long time to read in and out!