Construct object from boost serialization archive - c++

Is it possible to construct objects from directly from the archive?
Something like this...
// Non-working pseudo code
struct Foo {
BOOST_SERIALIZATION_SPLIT_MEMBER();
std::vector<int> data;
Foo() {
// populate "data" by doing calculation
data.push_back(1); data.push_back(2);
}
template<class Archive>
Foo( Archive & ar ) {
// populate "data" by rading the archive
}
template<class Archive>
void save(Archive & ar, const unsigned int version) const {
// Normal serialization of data
ar << data;
}
};
int main(int argc, const char *argv[])
{
// deserialize
boost::archive::text_iarchive oar(std::cin);
Foo foo(oar);
return 0;
}

You can use a deserializing constructor:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class Point
{
public:
Point() = default;
Point(boost::archive::text_iarchive& archive)
{
archive >> *this;
}
float x = 1.;
float y = 2.;
private:
friend class boost::serialization::access;
template<class TArchive>
void serialize(TArchive & archive, const unsigned int version)
{
archive & x;
archive & y;
}
};
int main()
{
Point p;
p.x = 5;
p.y = 6;
std::ofstream outputStream("test.archive");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << p;
outputStream.close();
std::ifstream inputStream("test.archive");
boost::archive::text_iarchive inputArchive(inputStream);
Point pointRead(inputArchive);
std::cout << pointRead.x << " " << pointRead.y << std::endl;
return 0;
}

As I said in the comment.
Yes there is no problem with constructing from an archive.
(Another alternative is to have static load function but that can have performance penalties).
The only potential problem I see with your approach is that your constructor can take almost anything as an argument and that can create problems.
And that can interfere with the copy constructor and other single argument constructors relying in implicit conversion.
So one has to restrict to take archives only.
There are different methods to do this, but based in this conversation http://marc.info/?l=boost&m=121131260728308&w=2, and by the fact that the inheritance tree of the archives is documented http://www.boost.org/doc/libs/1_35_0/libs/serialization/doc/class_diagram.html, I think this is the best solution is to check that the argument derives from basic_iarchive.
#include<type_traits>
struct Foo {
...
std::vector<int> data;
Foo() {
// populate "data" by doing calculation
data.push_back(1); data.push_back(2);
}
template<class IArchive,
typename = std::enable_if_t<std::is_base_of<boost::archive::detail::basic_iarchive, IArchive>::value>>
Foo( IArchive & ar ) {
ar >> data;
// populate "data" by reading the archive
}
...
};
int main(int argc, const char *argv[])
{
// deserialize
boost::archive::text_iarchive iar(std::cin);
Foo foo(iar); // will also work with other archives
}
As for what happens when your data is not default constructive see the discussion above.

Related

Common confusions with serializing polymorphic types

I have seen many questions, tutorials, and documentation involving serializing derived classes, and I haven't been able to reach a consensus on several issues, including (and illustrated in the following code):
boost::serialization::base_object vs BOOST_SERIALIZATION_BASE_OBJECT_NVP
archive & mData; vs archive & BOOST_SERIALIZATION_NVP(mData);
The usefulness of BOOST_SERIALIZATION_ASSUME_ABSTRACT(AbstractPoint);
Requiring serialize() for a class in the hierarchy that doesn't need to serialize anything.
Code:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/base_object.hpp>
#include <fstream>
class AbstractPoint
{
public:
virtual ~AbstractPoint(){}
virtual void DoSomething() = 0;
// Even though the class is abstract, we still need this
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// do nothing
}
};
// This doesn't seem to do anything
//BOOST_SERIALIZATION_ASSUME_ABSTRACT(AbstractPoint);
class Point : public AbstractPoint
{
public:
Point() = default;
Point(const double data) : mData(data) {}
void DoSomething(){}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// These two seem equivalent. Without one of them, unregistered void cast
archive & boost::serialization::base_object<AbstractPoint>(*this);
//archive & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AbstractPoint);
// These two seem equivalent
archive & mData;
//archive & BOOST_SERIALIZATION_NVP(mData);
}
double mData;
};
int main()
{
std::shared_ptr<AbstractPoint> point(new Point(7.4));
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive.register_type<Point>();
outputArchive << point;
outputStream.close();
std::shared_ptr<AbstractPoint> pointRead;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive.register_type<Point>();
inputArchive >> pointRead;
std::shared_ptr<Point> castedPoint = std::dynamic_pointer_cast<Point>(pointRead);
std::cout << castedPoint->mData << std::endl;
return 0;
}
The other major issue is where to register classes in a "real" environment (when there is linking, etc.), but that seems worth a separate question.
It would be great to have a "gold standard" example of these kinds of things in the documentation, but at the least on StackOverflow :)
boost::serialization::base_object vs BOOST_SERIALIZATION_BASE_OBJECT_NVP
The NVP wrapper is only ever required for archives that have element naming, like XML.
Unless you use it, base_object<> is cleaner and simpler.
archive & mData; vs archive & BOOST_SERIALIZATION_NVP(mData);
Ditto
The usefulness of BOOST_SERIALIZATION_ASSUME_ABSTRACT(AbstractPoint);
I assume it will merely be an optimization - suppressing registered type information with each archive type, since you told the framework it will never be de-serializing instances of the type
Requiring serialize() for a class in the hierarchy that doesn't need to serialize anything.
You don't need it, unless you need the type information about a polymorphic base there. When do you need that? When you need to de-serialize pointers of the base type.
Hence, if you have
struct A{ virtual ~A(); };
struct B:A{};
struct C:B{};
struct D:B{};`
you will need serialization for A (but not B) if you (de)serialize A*. You will need serialization for B if you (de)serialize B*.
Similarly, if your type is not polymorphic (virtual) or you don't use it as such, you don't need any base serialization (e.g. if you (de)serialize C or D directly).
Finally, if you have struct A{}; struct B:A{}; there is no need to tell Boost Serialization about the base type at all, (you could just do the serialization from within B).
Update in response to your samples:
case1.cpp looks ok
case2.cpp needs to call base serialization, of course; not necessarily using base_object because you require polymorphic serialization:
template<class TArchive> void serialize(TArchive& archive, unsigned) {
archive & boost::serialization::base_object<AbstractPoint>(*this)
& mData;
// OR:
archive & static_cast<AbstractPoint&>(*this)
& mData;
// OR even just:
archive & mParentData
& mData;
}
case3.cpp: indeed, it's exactly like case1, but with dynamic allocation and object tracking
case4.cpp: is exactly like case1, but with dynamic allocation and object tracking; NB!! it requires explicitly serializing for the base!
template<class TArchive> void serialize(TArchive& archive, unsigned) {
archive & boost::serialization::base_object<AbstractPoint>(*this)
& mData;
}
case5.cpp: yes, but it's more typical to use the CLASS_EXPORT* macros from boost/serialization/export.hpp
Bitrot insurance:
case1.cpp
case2.cpp
case3.cpp
case4.cpp
case5.cpp
Following #sehe's advice, here are some example uses:
Serialize derived class object, not forwarding to parent
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class AbstractPoint
{
public:
virtual ~AbstractPoint(){}
virtual void DoSomething() = 0;
};
class Point : public AbstractPoint
{
public:
Point() = default;
Point(const double data) : mData(data) {}
void DoSomething(){}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mData;
}
double mData;
};
int main()
{
Point point(7.4);
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << point;
outputStream.close();
Point pointRead;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> pointRead;
std::cout << pointRead.mData << std::endl;
return 0;
}
Serialize derived class object, including (automatic) forwarding to parent:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class AbstractPoint
{
public:
virtual ~AbstractPoint(){}
virtual void DoSomething() = 0;
double mParentData = 3.1;
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mParentData;
}
};
class Point : public AbstractPoint
{
public:
Point() = default;
Point(const double data) : mData(data) {}
void DoSomething(){}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// this is not required, the parent serialize() seems to be called automatically
// archive & boost::serialization::base_object<AbstractPoint>(*this);
archive & mData;
}
double mData;
};
int main()
{
Point point(7.4);
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << point;
outputStream.close();
Point pointRead;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> pointRead;
std::cout << pointRead.mParentData << std::endl;
std::cout << pointRead.mData << std::endl;
return 0;
}
Serialize derived class pointer, not forwarding to parent
(note nothing changes from the object case)
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <fstream>
class AbstractPoint
{
public:
virtual ~AbstractPoint(){}
virtual void DoSomething() = 0;
};
class Point : public AbstractPoint
{
public:
Point() = default;
Point(const double data) : mData(data) {}
void DoSomething(){}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mData;
}
double mData;
};
int main()
{
std::shared_ptr<Point> point(new Point(7.4));
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << point;
outputStream.close();
std::shared_ptr<Point> pointRead;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> pointRead;
std::cout << pointRead->mData << std::endl;
return 0;
}
Serialize derived class pointer, forwarding to parent
(note nothing changes from the object case)
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <fstream>
class AbstractPoint
{
public:
virtual ~AbstractPoint(){}
virtual void DoSomething() = 0;
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mParentData;
}
double mParentData = 3.1;
};
class Point : public AbstractPoint
{
public:
Point() = default;
Point(const double data) : mData(data) {}
void DoSomething(){}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mData;
}
double mData;
};
int main()
{
std::shared_ptr<Point> point(new Point(7.4));
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << point;
outputStream.close();
std::shared_ptr<Point> pointRead;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> pointRead;
std::cout << pointRead->mParentData << std::endl;
std::cout << pointRead->mData << std::endl;
return 0;
}
Serialize base class pointer
(We now have to register the type of the derived class with the archives, as well as use boost::serialization::base_object)
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/base_object.hpp>
#include <fstream>
class AbstractPoint
{
public:
virtual ~AbstractPoint(){}
virtual void DoSomething() = 0;
// This is required if we want to serialize an AbstractPoint pointer
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// do nothing
}
};
class Point : public AbstractPoint
{
public:
Point() = default;
Point(const double data) : mData(data) {}
void DoSomething(){}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
// Without this, we get unregistered void cast
archive & boost::serialization::base_object<AbstractPoint>(*this);
archive & mData;
}
double mData;
};
int main()
{
std::shared_ptr<AbstractPoint> point(new Point(7.4));
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive.register_type<Point>();
outputArchive << point;
outputStream.close();
std::shared_ptr<AbstractPoint> pointRead;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive.register_type<Point>();
inputArchive >> pointRead;
std::shared_ptr<Point> castedPoint = std::dynamic_pointer_cast<Point>(pointRead);
std::cout << castedPoint->mData << std::endl;
return 0;
}

Input stream error when partially deserializing derived class into base class using Boost

When I serialize a derived class using boost and try to deserialize only the base part, I get input stream error. I guess my code is wrong. Is there a way to deserialize only the base part of a derived object using boost archive?
Reason for this code is that I am trying to implement a design to send derived objects from one process to another. The receiving process will look at the ID in the base part to decide which derived object is received.
This is the test code with which I am trying to verify that this is possible using boost, but I get input stream error on executing this
class DataIface
{
public:
DataIface()
:num(0)
{
}
DataIface( int num):
num(num)
{
}
int num;
template< class Archive >
void serialize( Archive& ar, const unsigned int version )
{
std::cout<<"Serializing base class \n"<<std::endl;
ar & num;
}
};
class Data1 : public DataIface
{
private:
friend class boost::serialization::access;
public:
Data1()
:a(0)
{
};
Data1( int a, int num):
DataIface(num),
a(a)
{
}
int a;
template< class Archive >
void serialize( Archive& ar, const unsigned int version )
{
std::cout<<"Serializing derived class \n"<<std::endl;
ar & boost::serialization::base_object<DataIface>(*this);
ar & a;
}
};
int main()
{
Data1 obj(10, 20);
std::ostringstream oss;
boost::archive::text_oarchive oa( oss );
oa << obj;
Data1 obj2;
std::istringstream iss(oss.str());
boost::archive::text_iarchive ia( iss );
ia >> obj2;
cout<< obj2.a << std::endl;
cout << obj2.num << std::endl;
DataIface iface;
try
{
ia >> iface;
}
catch(std::exception& e)
{
std::cout<<e.what()<<std::endl;
}
cout << iface.num << std::endl;
return 0;
}
Any help would be appreciated
This is the test code that I am trying to verify that this is possible using boost and I get input stream error
What is the conclusion?
The conclusion is: it doesn't work. That's because it's not a feature. No where in the documentation does it even suggest you can do this.
Runtime Polymorphism
Just use polymorphism as intended!
Live On Coliru
#include <iostream>
#include <sstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/export.hpp>
class DataIface {
public:
virtual ~DataIface() {}
template <class Archive> void serialize(Archive &ar, const unsigned int version) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
class Data1 : public DataIface {
friend class boost::serialization::access;
public:
Data1(int a=0) : a(a) {}
int a;
template <class Archive> void serialize(Archive &ar, const unsigned int version) {
std::cout << __PRETTY_FUNCTION__ << "\n";
ar &boost::serialization::base_object<DataIface>(*this);
ar &a;
}
};
class Data2 : public DataIface {
friend class boost::serialization::access;
public:
Data2(int b=0) : b(b) {}
int b;
template <class Archive> void serialize(Archive &ar, const unsigned int version) {
std::cout << __PRETTY_FUNCTION__ << "\n";
ar &boost::serialization::base_object<DataIface>(*this);
ar &b;
}
};
BOOST_CLASS_EXPORT(Data1)
BOOST_CLASS_EXPORT(Data2)
int main() {
DataIface* tests[] = { new Data1(10), new Data2(-10) };
for(auto testobj : tests)
{
std::ostringstream oss;
{
boost::archive::text_oarchive oa(oss);
oa << testobj;
}
{
std::istringstream iss(oss.str());
boost::archive::text_iarchive ia(iss);
DataIface* obj = nullptr;
ia >> obj;
if (Data1* obj1 = dynamic_cast<Data1*>(obj))
std::cout << "It's a Data1: " << obj1->a << "\n";
if (Data2* obj2 = dynamic_cast<Data2*>(obj))
std::cout << "It's a Data2: " << obj2->b << "\n";
}
}
for(auto ptr : tests) delete ptr;
}
Prints:
void Data1::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_oarchive]
void DataIface::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_oarchive]
void Data1::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_iarchive]
void DataIface::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_iarchive]
It's a Data1: 10
void Data2::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_oarchive]
void DataIface::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_oarchive]
void Data2::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_iarchive]
void DataIface::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_iarchive]
It's a Data2: -10
Static Polymorphism
Alternatively, use a variant. This saves you the hassle of manual dynamic allocations and the potential cost of virtual dispatch.
Live On Coliru
#include <iostream>
#include <sstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/variant.hpp>
class Data1 {
friend class boost::serialization::access;
public:
Data1(int a=0) : a(a) {}
int a;
template <class Archive> void serialize(Archive &ar, const unsigned int version) {
ar &a;
}
friend std::ostream& operator<<(std::ostream& os, Data1 const& d) {
return os << "It's a Data1: " << d.a;
}
};
class Data2 {
friend class boost::serialization::access;
public:
Data2(int b=0) : b(b) {}
int b;
template <class Archive> void serialize(Archive &ar, const unsigned int version) {
ar &b;
}
friend std::ostream& operator<<(std::ostream& os, Data2 const& d) {
return os << "It's a Data2: " << d.b;
}
};
int main() {
using V = boost::variant<Data1, Data2>;
V tests[] = { Data1{10}, Data2{-10} };
for(auto testobj : tests)
{
std::ostringstream oss;
{
boost::archive::text_oarchive oa(oss);
oa << testobj;
}
{
std::istringstream iss(oss.str());
boost::archive::text_iarchive ia(iss);
V deserialized;
ia >> deserialized;
std::cout << deserialized << "\n";
}
}
}
This prints:
It's a Data1: 10
It's a Data2: -10

How do I serialize a class containing pointers to primitives?

I am trying to use boost's functionality for serializing pointers to primitives (so that I don't have to de-reference and do a deep store myself). However, I get a pile of errors when I try to do it. Here is a simple example of a class that is supposed to contain save and load methods which write and read the class content from a file. This program does not compile:
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <fstream>
class A
{
public:
boost::shared_ptr<int> sp;
int const * p;
int const& get() {return *p;}
void A::Save(char * const filename);
static A * const Load(char * const filename);
//////////////////////////////////
// Boost Serialization:
//
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar,const unsigned int file_version)
{
ar & p & v;
}
};
// save the world to a file:
void A::Save(char * const filename)
{
// create and open a character archive for output
std::ofstream ofs(filename);
// save data to archive
{
boost::archive::text_oarchive oa(ofs);
// write the pointer to file
oa << this;
}
}
// load world from file
A * const A::Load(char * const filename)
{
A * a;
// create and open an archive for input
std::ifstream ifs(filename);
boost::archive::text_iarchive ia(ifs);
// read class pointer from archive
ia >> a;
return a;
}
int main()
{
}
Note that I am not interested in a solution that dereferences the pointer; I want boost to take care of that for me (many of these classes might be pointing to the same underlying object).
In http://www.boost.org/doc/libs/1_54_0/libs/serialization/doc/index.html:
By default, data types designated primitive by Implementation Level
class serialization trait are never tracked. If it is desired to track
a shared primitive object through a pointer (e.g. a long used as a
reference count), It should be wrapped in a class/struct so that it is
an identifiable type. The alternative of changing the implementation
level of a long would affect all longs serialized in the whole program
- probably not what one would intend.
Hence:
struct Wrapped {
int value;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar,const unsigned int file_version)
{
ar & value;
}
};
boost::shared_ptr<Wrapped> sp;
Wrapped const * p;

Vector of pointers. BOOST serialization

I want to serialize/deserialize using BOOST the values (not the pointers) of objects in the following vector:
std :: vector <A*> m_vector;
To serialize I use the following code:
int nItems = m_vector.size();
ar & nItems;
std::for_each(m_vector.begin(), m_vector.end(), [&ar](A* pItem) {
ar & *pItem;
});
And to deserialize:
int nItems;
ar & nItems;
for (int i = 0; i < nItems; ++i) {
A* pItem;
ar & *pItem; ///////////// Run-Time Check Failure #3
m_vector.push_back(pItem);
}
But when I run the program I get the following error:
Run-Time Check Failure # 3 - The variable 'pItem' is Being Used without Being initialized.
What am I doing wrong?
Thank you.
You will need to allocate memory for the object pointed to by pItem:
A* pItem = new A;
ar & *pItem;
m_vector.push_back(pItem);
The error was because although you had a pointer, there was no object at the memory location where the pointer pointed to -- the value of the pointer was garbage (uninitialized pointer).
Don't forget to call delete when you no longer need the object pointed to by the pointer in the vector to preven memory leak. Better yet, use a smart pointer (e.g. boost::shared_ptr<>) to ensure the memory is deallocated when no longer accessible.
2 years later, but worth mentioning.
There's been a better solution to serialize a vector of pointers to objects or any other STL container (list, set etc.).
In order to serialize a vector, add:
#include <boost/serialization/vector.hpp>
and then you need to implement serialize() method and friend your class with archieve.
Everything is explained in this example (read all comments carefully, they're very important):
#include <fstream>
#include <iostream>
#include <vector>
#include <iostream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
class Abc{
// In order to make Abc serializable
// you need to friend this lass with serialization::access
friend class boost::serialization::access;
// and then add this method
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// choose what class fields do you want to serialize
ar & a;
ar & b;
ar & c;
}
public:
int a;
int b;
int c;
// don't forget about default constructor! It's necessary for serialization!
Abc(){};
Abc(int a, int b, int c): a(a), b(b), c(c){};
};
class GpsPosition
{
private:
// as mentioned above...
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & degrees;
ar & minutes;
ar & seconds;
ar & wektorIntow;
}
int degrees;
int minutes;
float seconds;
public:
std::vector<Abc*> abcVector;
GpsPosition(){};
GpsPosition(int d, int m, float s): degrees(d), minutes(m), seconds(s)
{
// adding some objects to abcVector
abcVector.push_back(new Abc(1, 2, 3));
abcVector.push_back(new Abc(3, 2, 3));
abcVector.push_back(new Abc(2, 2, 3));
abcVector.push_back(new Abc(1, 2, 3));
}
int getDegrees(){ return this->degrees; }
int getMinutes(){ return this->minutes; }
float getSeconds(){ return this->seconds; }
};
int main(){
// And now how to use it
// Saving to file:
std::ofstream fileHandler("filename");
const GpsPosition position1(35, 59, 24.567f);
{
boost::archive::text_oarchive boostOutputArchieve(fileHandler);
boostOutputArchieve << position1;
}
// Reading from file:
GpsPosition newPosition;
{
std::ifstream fileHandler;
try{
fileHandler.open("filenacme");
boost::archive::text_iarchive boostInputArchieve(fileHandler);
// read class state from archive
boostInputArchieve >> newPosition;
// archive and stream closed when destructors are called
fileHandler.close();
}
catch (std::ifstream::failure e) {
std::cerr << "Exception opening/reading/closing file";
}
catch(boost::archive::archive_exception e){
std::cerr << "Exception opening/reading/closing file";
}
}
// print to the console
std::cout << newPosition.getMinutes() << std::endl;
std::cout << newPosition.abcVector[0]->a;
std::cin.get();
return 0;
}
For more information, check out this tutorial:
http://www.boost.org/doc/libs/1_55_0/libs/serialization/doc/index.html

Boost Serializing of Object containing Map (with object values) and Multimap (with std::string values): what is needed?

See below a main() and two very simple classes. Then per Boost serialization (and what is shown) my questions are:
1) Does class B need the normal overloaded stream insertion operators '<<' and '>>' to be defined? Currently in my real code it doesn't have these.
2) Does class A in the store() and load() methods need to iterate through the map and multimap containers explicitely, storing/loading their key:value pairs explicitely?
e.g. something like:
void A::store(const char* filename){
std::ofstream ofs(filename);
boost::archive::text_oarchive oa(ofs);
std::map< std::string, B >::iterator it;
BMap.size();
oa << BMap.size();
for( it = BMap.begin(); it != BMap.end(); it++ ){
oa << it->first;
oa << it->second;
}
//similar for strMultimap
}
I assume that I don't need to do this, but am not certain.
3) Assuming class B has only the two data members shown, does it need a default contructor included explicitely? (as opposed to the implicit default constructor)
4) Does B need to have an overide for the comparison operator '>'? I assume that it doesn't since this is a very simple class.
Finally, any other comments per anything that I've failed to cover is appreciated!
Example code for my above questions:
//includes ommitted
int main() {
std::string file("test.dat");
A * pA = new A;
pA->store(file.c_str());
pA->fillMaps();
//release data
pA->load(file.c_str());
return 0;
}
//includes ommitted
class A
{
friend class boost::serialization::access;
public:
std::map< std::string, B > BMap;
std::multimap< std::string, std::string > strMultimap;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & BMap;
ar & strMultimap;
}
void store(const char* filename){
std::ofstream ofs(filename);
boost::archive::text_oarchive oa(ofs);
oa << this;
}
void load(const char* filename){
std::ifstream ifs(filename);
boost::archive::text_iarchive ia(ifs);
ia >> this;
}
void fillMaps(){
//code to allocate B objects and put them in BMap and fill strMultimap with whatever number of key:value pairs
}
class B
{
friend class boost::serialization::access;
public:
std::string str;
unsigned int num;
B::B(void)
: str("a string")
, num(7)
{
}
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & str;
ar & num;
}
}
1) You don't need stream operators for class B, but it does need a serialize() method. I had to wrap the serialization with the BOOST_SERIALIZATION_NVP (name value pair) macro:
ar & BOOST_SERIALIZATION_NVP(someNamedValue); // use this macro for everything you want to name
There might be a way to avoid naming your map, but I don't know how that's done.
2) No, class A doesn't need map-specific serialization code. Just make sure you include <boost/serialization/map.hpp>.
3) The implicit default constructor should be fine. You only ever need an explicit default constructor if a) you've already provided a non-default constructor or b) you want to change the behavior of the default constructor.
4) No operator < is needed :)
Here's some sample code which compiled, but I haven't run:
#include <boost/serialization/map.hpp>
struct A
{
struct B
{
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
}
};
typedef std::map<int, SomeClass> MyMap;
MyMap myMap;
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(myMap);
}
};