Practical examples of using Boost serialization

Listing1: Serialization of STL containers: a std::vector example using text archives

Your intuition may tell you to iterate through the STL container in order to serialize it, but it’s actually a lot simpler. First of all, be sure to include the necessary vector.hpp include file:

#include <boost/serialization/vector.hpp>;

And then simply serialize the std::vector data member(s):

template<class Archive>  
void serialize(Archive & ar, const unsigned int version)  
{  
  ar & filenames;      
}  
#include <iostream>
#include <vector>;
#include <fstream>;
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

class Info
{
private:
    // Allow serialization to access non-public data members.
    friend class boost::serialization::access;

    // Serialize the std::vector member of Info
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
      ar & filenames;    
    }
   
    std::vector<std::string> filenames;

public:
    void AddFilename( const std::string& filename );    
    void Print() const;
};

void Info::Print() const
{
    std::copy(filenames.begin(),     
              filenames.end(),     
              std::ostream_iterator<std::string>(std::cout, "\n"));     
}

void Info::AddFilename( const std::string& filename )
{
    filenames.push_back( filename );    
}

int main(int argc, char** argv) 
{
    Info info;
    info.AddFilename( "ThisFile.txt" );
    info.AddFilename( "ThatFile.txt" );
    info.AddFilename( "OtherFile.txt" );
    
    // Save filename data contained in Info object
    {
      // Create an output archive
      std::ofstream ofs( "store.dat" );
      boost::archive::text_oarchive ar(ofs);

      // Save the data
      ar & info;
    }
    
    // Restore from saved data and print to verify contents
    Info restored_info;
    {
        // Create and input archive
        std::ifstream ifs( "store.dat" );
        boost::archive::text_iarchive ar(ifs);

        // Load the data
        ar & restored_info;
    }
    
    restored_info.Print();

    return 0;
}

Giving you the following output from the restored Info data:

ThisFile.txt
ThatFile.txt
OtherFile.txt

Listing 2: Explicitly defining save and load functions

You may need to explicitly define the save and load functions whenever there is asymmetry, such as when versioning is involved. In other words when you don’t want to use the same serialize method to store and restore objects.

The is easily achieved by use of the BOOST_SERIALIZATION_SPLIT_MEMBER() macro, along with splitting the serialize method into separate save and load methods.

Full code listing as follows, which serializes the same Info object:

#include <iostream>
#include <vector>
#include <fstream>
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>;
#include <boost/serialization/split_member.hpp>

class Info
{
private:
    // Allow serialization to access non-public data members.
    friend class boost::serialization::access;

    template<class Archive>
    void save(Archive & ar, const unsigned int version) const 
    {
      ar & filenames;
    }

    template<class Archive>
    void load(Archive & ar, const unsigned int version) 
    {
      ar & filenames;
    }

    BOOST_SERIALIZATION_SPLIT_MEMBER()
   
    std::vector<std::string> filenames;

public:
    void AddFilename( const std::string& filename );    
    void Print() const;
};

void Info::Print() const
{
    std::copy(filenames.begin(),     
              filenames.end(),     
              std::ostream_iterator&lt;std::string>(std::cout, "\n"));     
}

void Info::AddFilename( const std::string& filename )
{
    filenames.push_back( filename );    
}

int main(int argc, char** argv) 
{
    Info info;
    info.AddFilename( "ThisFile.txt" );
    info.AddFilename( "ThatFile.txt" );
    info.AddFilename( "OtherFile.txt" );
    
    // Save filename data contained in Info object
    {
      // Create an output archive
      std::ofstream ofs( "store.dat" );
      boost::archive::text_oarchive ar(ofs);

      // Save the data
      ar & info;
    }
    
    // Restore from saved data and print to verify contents
    Info restored_info;
    {
        // Create and input archive
        std::ifstream ifs( "store.dat" );
        boost::archive::text_iarchive ar( ifs );

        // Load the data
        ar & restored_info;
   }
    
    restored_info.Print();

    return 0;
}

Giving you the following output from the restored Info data:

ThisFile.txt
ThatFile.txt
OtherFile.txt

Listing 3: Saving and loading multiple objects

The same as listing 2, but what if we wish to save multiple versions of the Info object. This shows you how:

#include <iostream>
#include <vector>  
#include <fstream>   
#include <boost/serialization/vector.hpp>   
#include <boost/archive/text_oarchive.hpp>   
#include <boost/archive/text_iarchive.hpp>   
#include <boost/serialization/split_member.hpp>  
  
class Info  
{  
private:  
    // Allow serialization to access non-public data members.  
    friend class boost::serialization::access;  
  
    template<class Archive>  
    void save(Archive & ar, const unsigned int version) const   
    {  
      ar & filenames;  
    }  
  
    template<class Archive> 
    void load(Archive & ar, const unsigned int version)   
    {  
      ar & filenames;  
    }  
  
    BOOST_SERIALIZATION_SPLIT_MEMBER()  
     
    std::vector<std::string> filenames;  
  
public:  
    void AddFilename( const std::string& filename );      
    void Print() const;  
};  
  
void Info::Print() const  
{  
    std::copy(filenames.begin(),       
              filenames.end(),       
              std::ostream_iterator<std::string>(std::cout, "\n"));       
}  
  
void Info::AddFilename( const std::string& filename )  
{  
    filenames.push_back( filename );      
}  
  
int main(int argc, char** argv)   
{ 
	std::vector<Info> infs;

    Info info1, info2;  
    info1.AddFilename( "ThisFile.txt" );  
    info2.AddFilename( "ThatFile.txt" );  
    info2.AddFilename( "OtherFile.txt" );  

	info2.AddFilename( "ABC" );
	info2.AddFilename( "123" );
	info2.AddFilename( "XYZ" );

	infs.push_back( info1 );
	infs.push_back( info2 );
      
    // Save filename data contained in Info object  
    {  
      // Create an output archive  
      std::ofstream ofs( "store.dat" );  
      boost::archive::text_oarchive ar(ofs);  
  
      // Save the data  
      ar & infs;  
    }  
      
    // Restore from saved data and print to verify contents  
    std::vector<Info> restored_info;  
    {  
        // Create and input archive  
        std::ifstream ifs( "store.dat" );  
        boost::archive::text_iarchive ar( ifs );  
  
        // Load the data  
        ar & restored_info;  
   }  
     
        std::vector<Info>::const_iterator it = restored_info.begin();
	for (; it != restored_info.end(); ++it)
	{
		Info info = *it;
		info.Print();
	}
   
    return 0;  
} 

Giving the following output:

BoostSerialize

Related post:

Serializing data in MFC / Visual C++