Cereal seems to not properly serialize an std::string - c++

I am trying to serialize a class into a binary, to that effect I first started trying to serialize an std::string member within the class, I wrote this serialization method:
template<typename Archive>
void ShaderProgram::serialize(Archive& archive, ShaderProgram& program)
{
archive(CEREAL_NVP(program.program_name));
}
Then I am trying to serialize and immediately read the class:
ShaderProgram program;
std::filesystem::create_directories(fs::path(cached_shader_path).parent_path());
std::ofstream os(cached_shader_path, std::ios::binary);
cereal::BinaryOutputArchive archive_out( os );
ShaderProgram::serialize(archive_out, program);
std::ifstream is(cached_shader_path, std::ios::binary);
cereal::BinaryInputArchive archive_in( is );
ShaderProgram::serialize(archive_in, program);
Which results in:
terminate called after throwing an instance of 'cereal::Exception'
what(): Failed to read 8 bytes from input stream! Read 0
The class I am testing this with is trivial:
struct ShaderProgram
{
std::string program_name = "name";
template<typename Archive>
static void serialize(Archive& archive, ShaderProgram& program);
};
template<typename Archive>
void ShaderProgram::serialize(Archive& archive, ShaderProgram& program)
{
archive(CEREAL_NVP(program.program_name));
}
I don;t understand why this fails.

Here is an example. All is fine with cereal. In plain C++ remove Rcpp connections.
// [[Rcpp::depends(Rcereal)]]
#include <string>
#include <fstream>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/access.hpp>
#include <Rcpp.h>
struct ShaderProgram
{
ShaderProgram(){};
ShaderProgram(std::string program_name)
: program_name{program_name}{};
~ShaderProgram() = default;
std::string get_program_name() const {
return program_name;
}
private:
std::string program_name{};
friend class cereal::access;
template<class Archive>
void serialize(Archive& archive)
{
archive(program_name);
}
};
// [[Rcpp::export]]
int main() {
{
ShaderProgram sp("King Kong 8");
std::ofstream os("Backend/Serialize_StringProgram.bin", std::ios::binary);
cereal::BinaryOutputArchive oarchive(os);
oarchive(sp);
}
{
ShaderProgram sp{};
std::ifstream is("Backend/Serialize_StringProgram.bin", std::ios::binary);
cereal::BinaryInputArchive iarchive(is);
iarchive(sp);
Rcpp::Rcout << sp.get_program_name() << std::endl;
}
}

Related

boost::serialization of static array / archive exception on restore

The following code compiles and seems to serialize properly (that is, the static is saved only once apparently). However, it has an 'input stream error' exception on restore:
#include <boost/serialization/tracking.hpp>
#include <boost/serialization/level.hpp>
#include <boost/serialization/array.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <iostream>
#include <fstream>
#include <array>
class SA {
std::array<char, 1024*1024> sbuf;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int ver) {
ar & boost::serialization::make_array(sbuf.data(), sbuf.size());
};
};
BOOST_CLASS_IMPLEMENTATION(SA, boost::serialization::object_serializable); // serialization_level
BOOST_CLASS_TRACKING(SA, boost::serialization::track_always); // tracking_level
class Foo {
char buf[1024];
inline static SA sxbuf;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int ver) {
ar & boost::serialization::make_array(buf, sizeof(buf));
ar & sxbuf;
};
};
class FooList {
std::array<Foo, 100> fool;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int ver) {
ar & boost::serialization::make_array(fool.data(), fool.size());
};
};
int
main()
{
const std::string filename{"foo.sav"};
FooList x;
std::ofstream out{filename, std::ios::binary};
boost::archive::binary_oarchive oa(out);
oa << x;
std::cout << "Saved\n";
std::ifstream ifs{filename};
boost::archive::binary_iarchive ia(ifs);
if (ifs.fail()) {
std::cerr << "couldn't open input file " << filename << "\n";
return 1;
}
ia >> x; // gives exception
std::cout << "Restored\n";
return 0;
}
The output is as follows:
Saved
terminate called after throwing an instance of 'boost::archive::archive_exception'
what(): input stream error
(I tried this on godbolt too, but -lboost_serialization didn't seem to work, so it wouldn't link properly... possibly my error there).
Any insight much appreciated...
This opens an archive before the writing end is finalized:
std::ofstream out{filename, std::ios::binary};
boost::archive::text_oarchive oa(out);
oa << x;
std::cout << "Saved\n";
std::ifstream ifs{filename};
Also ifs is missing the ios::binary flag.
Other than that, you can
drop make_array,
prefer std::array over T[] and
default the serialization level.
Live On Coliru
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/array.hpp>
#include <array>
#include <fstream>
#include <iostream>
class SA {
std::array<char, 1024 * 1024> sbuf;
friend class boost::serialization::access;
template <class Ar> void serialize(Ar &ar, unsigned) { ar &sbuf; }
};
BOOST_CLASS_TRACKING(SA, boost::serialization::track_always) // tracking_level
class Foo {
std::array<char, 1024> buf;
inline static SA sxbuf;
friend class boost::serialization::access;
template <class Ar> void serialize(Ar &ar, unsigned) { ar &buf &sxbuf; }
};
class FooList {
std::array<Foo, 100> fool;
friend class boost::serialization::access;
template <class Ar> void serialize(Ar &ar, unsigned) { ar &fool; }
};
int main() {
const std::string filename{"foo.sav"};
{
std::ofstream out(filename, std::ios::binary);
boost::archive::binary_oarchive oa(out);
FooList x{};
oa << x;
std::cout << "Saved\n";
}
{
std::ifstream ifs(filename, std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
FooList x{};
ia >> x; // gives exception
std::cout << "Restored\n";
}
}
Prints
Saved
Restored

Boost Serialization throws exception while reading from binary

I have found this code and trying to modify it for binary object serialization on visual studios. But on doing so it throws exception
"Unhandled exception at 0x00007FFF269954D8 in Boost_Serialization.exe: Microsoft C++ exception: std::length_error at memory location 0x000000829D94F7B0."
Not sure what's wrong.
#include <iostream>
#include <vector>
#include <fstream>
#include <boost/serialization/vector.hpp>
#include<boost/archive/binary_oarchive.hpp>
#include<boost/archive/binary_iarchive.hpp>
#include<boost/serialization/binary_object.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
{
std::ofstream Obj_ofstream("data.dat", std::ios::binary);
boost::archive::binary_oarchive op_archive(Obj_ofstream);
op_archive << boost::serialization::make_binary_object(&infs, sizeof(infs));
//Obj_ofstream.close();
}
// Restore from saved data and print to verify contents
std::vector<Info> restored_info;
{
std::ifstream Obj_ifstream("data.dat", std::ios::binary);
boost::archive::binary_iarchive ip_archive(Obj_ifstream);
ip_archive >> restored_info;
//Obj_ifstream.close();
}
//std::vector<Info>::const_iterator it = restored_info.begin();
//for (; it != restored_info.end(); ++it)
//{
// Info info = *it;
// info.Print();
//}
std::cout << "Testing : " << std::endl;
return 0;
You use BOOST_SERIALIZATION_SPLIT_MEMBER() and do not implement save method. However, you do not need to do that. Remove splitting and implement general void serialize(Archive & ar, const unsigned int version) method (note to include new header for vector serialization). It will look like this and run like a charm:
#include <iostream>
#include <vector>
#include <fstream>
#include <boost/serialization/vector.hpp>
#include<boost/archive/binary_oarchive.hpp>
#include<boost/archive/binary_iarchive.hpp>
#include<boost/serialization/binary_object.hpp>
#include<boost/serialization/vector.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 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)
{
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
{
std::ofstream Obj_ofstream("data.dat", std::ios::binary);
boost::archive::binary_oarchive op_archive(Obj_ofstream);
op_archive << infs;
//Obj_ofstream.close();
}
// Restore from saved data and print to verify contents
std::vector<Info> restored_info;
{
std::ifstream Obj_ifstream("data.dat", std::ios::binary);
boost::archive::binary_iarchive ip_archive(Obj_ifstream);
ip_archive >> restored_info;
//Obj_ifstream.close();
}
std::vector<Info>::const_iterator it = restored_info.begin();
for (; it != restored_info.end(); ++it)
{
Info info = *it;
info.Print();
}
std::cout << "Testing : " << std::endl;
system("PAUSE");
return 0;
}

C++ Cereal save/load_and_construct not working

So I'm trying to use the Cereal library and I've come to an issue I can't seem to overcome. Essentially the doc's say it is possible to deserialize Types with no default constructor. Yet in the implementation notes it says Define a serialize or save/load pair as you normally would yet the serialize/load options cannot be defined in a valid manner if there is no default constructor. I take this to mean, the load_and_construct function takes the place of load. Yet when implementing a relatively simple example seen below.
"main.cpp"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <memory>
#include <cereal/access.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/portable_binary.hpp>
struct string_wrapper {
const std::string str;
string_wrapper(const std::string& _a) : str{_a} {}
template <class Archive>
void save(Archive& _archive) const {
_archive(str);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<string_wrapper>& _construct) {
std::string a;
_archive(a);
_construct(a);
}
};
struct wrapper_of_string_wrappers {
const std::vector<string_wrapper> strs;
wrapper_of_string_wrappers(
const std::vector<string_wrapper>& _a
) : strs{_a} { }
template <class Archive>
void save(Archive& _archive) const {
_archive(strs);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<wrapper_of_string_wrappers>& _construct) {
std::vector<string_wrapper> strs;
_archive(strs);
_construct(strs);
}
};
int main() {
auto file = "test.bin";
{ // save
std::ofstream os(file, std::ios::binary);
cereal::PortableBinaryOutputArchive archiveSave(os);
std::vector<string_wrapper> as;
as.push_back({"Hello"});
as.push_back({"World"});
wrapper_of_string_wrappers test(as);
auto test_ptr = std::make_unique<wrapper_of_string_wrappers>(test);
archiveSave(test_ptr);
}
{ // load
std::ifstream is(file, std::ios::binary);
cereal::PortableBinaryInputArchive archiveLoad(is);
std::unique_ptr<wrapper_of_string_wrappers> test = nullptr;
archiveLoad(test);
std::cout << (*test).strs[0].str << " " << (*test).strs[1].str << std::endl;
}
std::cin.get();
return 0;
}
This code obviously is kind of pointless, its just a minimal example to illustrate the problem I'm running into.
From this page
Non-default constructors are currently only supported for serializing pointers
Your problem here is you are trying to serialize non pointer values with no default constructor here
std::vector<string_wrapper> strs;
_archive(strs);
To solve your problem you need either make default constructor for string_wrapper with save/load pair or use string_wrapper as pointer in wrapper_of_string_wrappers.
Here is working code for second option(string_wrapper remains same):
struct wrapper_of_string_wrappers {
//const std::vector<std::unique_ptr<string_wrapper>> strs;
//const string_wrapper strs;
const std::unique_ptr<string_wrapper> strs;
wrapper_of_string_wrappers(
//const std::vector<std::unique_ptr<string_wrapper>>& _a
const string_wrapper _a
) : strs{ new string_wrapper(_a) } { }
wrapper_of_string_wrappers(
const wrapper_of_string_wrappers& w
) : strs{ new string_wrapper(*w.strs) } { }
template <class Archive>
void save(Archive& _archive) const {
_archive(strs);
}
template <class Archive>
static void load_and_construct(Archive& _archive,
cereal::construct<wrapper_of_string_wrappers>& _construct) {
//std::vector<std::unique_ptr<string_wrapper>> strs;
std::unique_ptr<string_wrapper> strs;
_archive(strs);
_construct(*strs);
}
};
int main() {
auto file = "test.bin";
{ // save
std::ofstream os(file, std::ios::binary);
cereal::PortableBinaryOutputArchive archiveSave(os);
string_wrapper as("Hello");
wrapper_of_string_wrappers test(as);
auto test_ptr = std::make_unique<wrapper_of_string_wrappers>(test);
archiveSave(test_ptr);
}
{ // load
std::ifstream is(file, std::ios::binary);
cereal::PortableBinaryInputArchive archiveLoad(is);
std::unique_ptr<wrapper_of_string_wrappers> test = nullptr;
archiveLoad(test);
std::cout << (*test).strs->str << std::endl;
}
std::cin.get();
return 0;
}

Deserializing STL container of type with no default constructor

I've recently learned the pattern of the deserializing constructor (Deserializing constructor doesn't read data correctly) to use serialization with types that do not have default constructors. Now I'm trying to serialize an STL container of these objects, as in the example below:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/vector.hpp>
#include <fstream>
class Point
{
public:
Point(double x) : mX(x) {}
template<class TArchive>
Point(TArchive& archive)
{
archive >> *this;
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mX;
}
double mX;
};
int main()
{
std::vector<Point> pointVector;
pointVector.push_back(Point(1));
pointVector.push_back(Point(2));
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << pointVector;
outputStream.close();
std::vector<Point> readPointVector;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> readPointVector; // Compiler error - no matching function call to Point::Point()
return 0;
}
It seems clear that this shouldn't work, but how would I tell the archive that it needs to use the deserializing constructor to construct the objects that it reads before adding them to the container?
---------- EDIT ----------
After implementing the suggestion in the only answer, this code compiles fine, but doesn't seem to deserialize correctly. The readPointVector only has size 1 but it should have size 2 (and the data is not correct in the one object that it does contain):
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <fstream>
class Point
{
public:
Point(double x) : mX(x) {}
template<class TArchive>
Point(TArchive& archive)
{
archive >> *this;
}
template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
archive & mX;
}
double mX;
};
template <typename Archive>
Archive& operator >> (Archive& archive, std::vector<Point>& points)
{
points.emplace_back(archive);
return archive;
}
int main()
{
std::vector<Point> pointVector;
pointVector.push_back(Point(5.6));
pointVector.push_back(Point(7.8));
std::cout << pointVector.size() << std::endl; // outputs 2
{
std::ofstream outputStream("test.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << pointVector;
outputStream.close();
}
std::vector<Point> readPointVector;
std::ifstream inputStream("test.txt");
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> readPointVector;
std::cout << readPointVector.size() << std::endl; // outputs 1 (and readPointVector[0].mX is 2, but should be 7.8)
return 0;
}
You may specialize for vector of Points:
template <typename Archive>
Archive& operator >> (Archive& archive, std::vector<Point>& points)
{
points.emplace_back(archive);
return archive;
}

correct type-cast for boost de-serializations of different derived classes

In my application, there are agents of different types. I am planning to use boost serialization for sending/receiving data between agents.(by sending/receiving, I actually mean writing/reading operation the serialization target file)
A receiving agent may receive data of different data whose type is not known in advance. Suppose the data format has a general structure like this:
class Base
{
public:
int message_type_id;
}
class Derived_1
{
public:
Derived_1(int message_type_id_):message_type_id(message_type_id_){}
struct data_1 {...};
};
class Derived_2
{
public:
Derived_2(int message_type_id_):message_type_id(message_type_id_){}
struct data_2 {...};
};
the sending agent can send(i.e serialize) any of the two derived types. Similarly, the receiving agent can receive(i.e de-serialize) any of the two derived types; while what I can see in the tutorial(Dumping derived classes through base class pointers) is like this:
void save()
{
std::ofstream file("archive.xml"); //target file
boost::archive::xml_oarchive oa(file);
oa.register_type<date>( );// you know what you are sending, so you make proper modifications here to do proper registration
base* b = new date(15, 8, 1947);
oa & BOOST_SERIALIZATION_NVP(b);
}
void load()
{
std::ifstream file("archive.xml"); //target file
boost::archive::xml_iarchive ia(file);
ia.register_type<date>( );// I don't know which derived class I am receiving, so I can't do a proper registration
base *dr;
ia >> BOOST_SERIALIZATION_NVP(dr);
date* dr2 = dynamic_cast<date*> (dr);
std::cout << dr2;
}
as you can see, xml_oarchive and xml_iarchive do a register_type<date> before serialize/deserialization. so the receiving end will know in advance what to dynamic_cast to.
whereas in my case, since I know what I am sending, I can do proper registration&serialization on case-to-case basis. However, on the receiving end, I dont't know in advance what to register and what to dynamic cast.
Is there a way I can tell the type in advance so that the receiving can do a casting?
thanks
EDIT:
Here is the simplified modification of demo.cpp I save an object, and then restore it.
#include <cstddef> // NULL
#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <boost/archive/tmpdir.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/assume_abstract.hpp>
/*
bus_stop is the base class.
bus_stop_corner and bus_stop_destination are derived classes from the above base class.
bus_route has a container that stores pointer to the above derived classes
*/
class bus_stop
{
friend class boost::serialization::access;
virtual std::string description() const = 0;
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & type;
}
protected:
public:
std::string type;
bus_stop(){type = "Base";}
virtual ~bus_stop(){}
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(bus_stop)
class bus_stop_corner : public bus_stop
{
friend class boost::serialization::access;
virtual std::string description() const
{
return street1 + " and " + street2;
}
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
// save/load base class information
ar & boost::serialization::base_object<bus_stop>(*this);
ar & street1 & street2;
}
public:
std::string street1;
std::string street2;
bus_stop_corner(){}
bus_stop_corner(
const std::string & _s1, const std::string & _s2
) :
street1(_s1), street2(_s2)
{
type = "derived_bs_corner";
}
};
class bus_stop_destination : public bus_stop
{
friend class boost::serialization::access;
virtual std::string description() const
{
return name;
}
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::base_object<bus_stop>(*this) & name;
}
public:
std::string name;
bus_stop_destination(){}
bus_stop_destination(
const std::string & _name
) :
name(_name)
{
type = "derived_bs_destination";
}
};
class bus_route
{
friend class boost::serialization::access;
typedef bus_stop * bus_stop_pointer;
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar.register_type(static_cast<bus_stop_corner *>(NULL));
ar.register_type(static_cast<bus_stop_destination *>(NULL));
ar & stops;
}
public:
std::list<bus_stop_pointer> stops;
bus_route(){}
void append(bus_stop *_bs)
{
stops.insert(stops.end(), _bs);
}
};
//BOOST_CLASS_VERSION(bus_route, 2)
void save_schedule(const bus_route s, const char * filename){
// make an archive
std::ofstream ofs(filename);
boost::archive::text_oarchive oa(ofs);
oa << s;
}
void
restore_schedule(bus_route &s, const char * filename)
{
// open the archive
std::ifstream ifs(filename);
boost::archive::text_iarchive ia(ifs);
// restore the schedule from the archive
ia >> s;
}
int main(int argc, char *argv[])
{
bus_stop *bs1 = new bus_stop_corner(
"First St", "Second st"
);
bus_stop *bs2 = new bus_stop_destination(
"myName"
);
// make a routes
bus_route original_route;
original_route.append(bs1);
original_route.append(bs2);
std::string filename1(boost::archive::tmpdir());
filename1 += "/demofile1.txt";
save_schedule(original_route, filename1.c_str());
bus_route new_route ;
restore_schedule(new_route, filename1.c_str());
////////////////////////////////////////////////////////
std::string filename2(boost::archive::tmpdir());
filename2 += "/demofile2.txt";
save_schedule(new_route, filename2.c_str());
delete bs1;
delete bs2;
return 0;
}
The old and new objects are not equal coz again saving(serializing) the new object to another file results in a different(empty) content. Can you please let me know how I can fix this code to deserialize the derived classes successfully? many thanks
EDIT-2
There is nothing wrong with the above code now(after a small typo was fixed).
I am answering my own question here coz there is another good approach suggested by someone else.
So the Answer to my first question is like this :
As long as you register the derived types in the main serialization function (in the above case: serialize() in bus_route class) everything should be fine.
thanks for all the help
A solution is to (de-)serialize boost::shared_ptr<Base>. The following code demonstrates it. After deserialization the pDst is an instance of the Derived_1 class. The code complied using an online compiler is available on this link.
#include <boost/serialization/access.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
class Base {
friend class boost::serialization::access;
public:
Base();
virtual ~Base();
private:
template<class Archive> void serialize(Archive &ar, const unsigned int version) {}
public:
virtual bool operator ==(const Base &rh) const = 0;
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Base)
BOOST_SERIALIZATION_SHARED_PTR(Base)
Base::Base() {
}
Base::~Base() {
}
class Derived_1 : boost::noncopyable, public Base {
friend class boost::serialization::access;
public:
int m_iValue;
public:
Derived_1();
Derived_1(int iValue);
private:
template<class Archive> void serialize(Archive &ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
ar & boost::serialization::make_nvp("value", m_iValue);
}
public:
bool operator ==(const Base &rh) const;
};
BOOST_SERIALIZATION_SHARED_PTR(Derived_1)
Derived_1::Derived_1() : m_iValue(0) {
}
Derived_1::Derived_1(int iValue) : m_iValue(iValue) {
}
bool Derived_1::operator==(const Base &rh) const {
const Derived_1 *pRH = dynamic_cast<const Derived_1 *>(&rh);
return pRH != nullptr && pRH->m_iValue == this->m_iValue;
}
#include <boost/serialization/export.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/make_shared.hpp>
#include <sstream>
#include <string>
BOOST_CLASS_EXPORT_GUID(Base, "base")
BOOST_CLASS_EXPORT_GUID(Derived_1, "derived_1")
void test(void) {
std::string str;
boost::shared_ptr<Base> pSrc = boost::make_shared<Derived_1>(10);
boost::shared_ptr<Base> pDst;
{
std::ostringstream ofs;
boost::archive::xml_oarchive oa(ofs);
oa << boost::serialization::make_nvp("item", pSrc);
str = ofs.str();
}
{
std::istringstream ifs(str);
boost::archive::xml_iarchive ia(ifs);
ia >> boost::serialization::make_nvp("item", pDst);
}
if (*pSrc == *pDst) {
printf("Success\n");
}
else {
printf("Fail\n");
}
}
int main(int argc, char* argv[]) {
test();
}