Can boost::container::strings be serialized using boost serialization? - c++

I am attempting to serialize a class which contains a boost::container::string
#include <iostream>
#include <cstdlib>
#include <boost/container/string.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
class car
{
public:
car() {}
car(boost::container::string make) : make(make) {}
boost::container::string make;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & make;
}
};
int main()
{
car my_car("ford");
std::stringstream ss;
boost::archive::text_oarchive oa(ss);
oa << my_car;
car new_car;
boost::archive::text_iarchive ia(ss);
ia >> new_car;
}
But the above fails to compile with the following error:
boost/serialization/access.hpp:116:11: error: 'class boost::container::basic_string<char>' has no member named 'serialize'
The same code can be changed to use std::string and it compiles fine.
Can boost::container::strings be serialized and if so what am I doing incorrectly or missing?

Yes. Surprisingly, the necessary support is not baked into Boost. Though if you look inside the string serialization header you will find that it has support as "primitive", and it takes just one line to enable it:
BOOST_CLASS_IMPLEMENTATION(boost::container::string, boost::serialization::primitive_type)
Now it works the same as std::string:
Live On Coliru
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/container/string.hpp>
#include <iostream>
BOOST_CLASS_IMPLEMENTATION(boost::container::string, boost::serialization::primitive_type)
struct car {
template<class Ar> void serialize(Ar& ar, unsigned) { ar & make; }
boost::container::string make;
};
int main() {
std::stringstream ss;
{
boost::archive::text_oarchive oa(ss);
car my_car{"ford"};
oa << my_car;
} // close archive
std::cout << ss.str() << "\n";
boost::archive::text_iarchive ia(ss);
car new_car;
ia >> new_car;
}
Prints
22 serialization::archive 17 0 0 ford

Related

static_assert failed "typex::value" failure while deserialising binary data using boost

The code below serialises and de serialises the class and structure's members.
The serialisation is working but i have encountered the below error while trying to deserialise it using oarch >> BOOST_SERIALIZATION_NVP(outObj);
Is there any big miss in the code that i have not realiased and not implemented .
In file included from main.cpp:1:
In file included from /usr/local/include/boost/archive/binary_oarchive.hpp:21:
In file included from /usr/local/include/boost/archive/binary_oarchive_impl.hpp:22:
In file included from /usr/local/include/boost/archive/basic_binary_oarchive.hpp:33:
In file included from /usr/local/include/boost/archive/detail/common_oarchive.hpp:22:
In file included from /usr/local/include/boost/archive/detail/interface_oarchive.hpp:23:
In file included from /usr/local/include/boost/archive/detail/oserializer.hpp:68:
/usr/local/include/boost/archive/detail/check.hpp:162:5: error: static_assert failed "typex::value"
BOOST_STATIC_ASSERT(typex::value);
^ ~~~~~~~~~~~~
/usr/local/include/boost/static_assert.hpp:70:41: note: expanded from macro 'BOOST_STATIC_ASSERT'
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <map>
#include <boost/serialization/map.hpp>
#include <boost/serialization/split_member.hpp>
struct values
{
std::string name;
std::string sex;
values():name("dummy"),sex("dummy"){} ;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(name);
ar & BOOST_SERIALIZATION_NVP(sex);
}
};
class Myclass
{
public:
Myclass()
{
values val1;
e_group.insert( std::make_pair(1,val1) ) ;
e_group.insert( std::make_pair(2,val1) ) ;
p_group.insert( std::make_pair(1,e_group) ) ;
p_group.insert( std::make_pair(2,e_group) ) ;
}
template<class Archive>
void serialize(Archive & ar, const unsigned int version) const
{
ar & BOOST_SERIALIZATION_NVP(e_group);
ar & BOOST_SERIALIZATION_NVP(p_group);
}
typedef std::map<int,values> groups;
typedef std::map<int,groups> Pgroups;
groups e_group;
Pgroups p_group;
};
int main()
{
Myclass assetlist;
auto os = std::ostringstream(std::ios::binary);
boost::archive::binary_oarchive arch( os, boost::archive::no_header);
arch << BOOST_SERIALIZATION_NVP(assetlist);
std::string s1 = os.str();
std::stringstream is( s1, std::ios_base::binary| std::ios_base::out| std::ios_base::in);
Myclass outObj;
boost::archive::binary_iarchive iarch (is , boost::archive::no_header );
iarch >> BOOST_SERIALIZATION_NVP(outObj);
return 0;
}
Your static assert fails because of the extra 'const' in Myclass::serialize function.
It should look like:
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{ ... }
Conserning the BOOST_SERIALIZATION_NVP() usage see this question.

Boost serialization unable to restore saved objects

This is how my class looks:
#include <iostream>
#include <boost/dynamic_bitset/dynamic_bitset.hpp>
#include <vector>
#include <fstream>
// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
using namespace std;
using namespace boost;
class outer{
friend class boost::serialization::access;
public:
int a;
class inner{
friend class boost::serialization::access;
public:
int a;
inner(int a){
this->a = a;
}
template<class Archive>
void serialize(Archive & ar,const unsigned int version){
ar & a;
}
inner(){
}
};
vector<inner> inners;
outer(int a){
this->a = a;
inners.push_back(inner(this->a+1));
}
outer(){
}
template<class Archive>
void serialize(Archive & ar,const unsigned int version){
ar & a;
ar & inners;
}
};
vector<outer> outers;
vector<outer> _outers;
BOOST_CLASS_EXPORT(outer);
int main(int, char*[]) {
int i;
std::ofstream ofs("filename.dat");
for(i=0;i<5;i++)
outers.push_back(outer(i));
boost::archive::text_oarchive oa(ofs);
oa << outers;
std::ifstream ifs("filename.dat");
boost::archive::text_iarchive ia(ifs);
// read class state from archive
ia >> _outers;
return EXIT_SUCCESS;
}
I create a vector of outer class instances and write it out to a text stream (which seems to work fine). But when I read it back, I get the error:
terminate called after throwing an instance of 'boost::archive::archive_exception'
what(): input stream error
The above is the entire self-contained code, compiled with:
g++ -I /path/to/boost test.cpp -lboost_serialization
How do I fix this, any ideas?
Missing:
#include <boost/serialization/export.hpp>
You need to close the output archive/stream before reading the file back:
int main() {
{
std::ofstream ofs("filename.dat");
std::vector<outer> outers(5);
std::iota(outers.begin(), outers.end(), 0u);
{
boost::archive::text_oarchive oa(ofs);
oa << outers;
}
}
{
// read class state from archive
std::vector<outer> _outers;
std::ifstream ifs("filename.dat");
boost::archive::text_iarchive ia(ifs);
ia >> _outers;
for(auto& outer : _outers) {
std::cout << "outer " << outer.a << "\n";
for (auto& inner: outer.inners)
std::cout << " inner " << inner.a << "\n";
}
}
}
Full Demo
Live On Coliru
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
#include <fstream>
class outer {
friend class boost::serialization::access;
public:
int a;
class inner {
friend class boost::serialization::access;
public:
int a;
inner(int a) { this->a = a; }
template <class Archive> void serialize(Archive &ar, unsigned) { ar &a; }
inner() {}
};
std::vector<inner> inners;
outer(int a = 0) : a(a), inners {a+1} { }
template <class Archive> void serialize(Archive &ar, unsigned) {
ar &a;
ar &inners;
}
};
BOOST_CLASS_EXPORT(outer)
int main(int, char *[]) {
{
std::ofstream ofs("filename.dat");
std::vector<outer> outers(5);
std::iota(outers.begin(), outers.end(), 0u);
{
boost::archive::text_oarchive oa(ofs);
oa << outers;
}
}
{
// read class state from archive
std::vector<outer> _outers;
std::ifstream ifs("filename.dat");
boost::archive::text_iarchive ia(ifs);
ia >> _outers;
for(auto& outer : _outers) {
std::cout << "outer " << outer.a << "\n";
for (auto& inner: outer.inners)
std::cout << " inner " << inner.a << "\n";
}
}
}
Prints
outer 0
inner 1
outer 1
inner 2
outer 2
inner 3
outer 3
inner 4
outer 4
inner 5

Boost C++ xml_oarchive Run-Time Check Failure #2 - Stack around the variable was corrupted

I'm very new to Boost serialization. I'm using Boost to serialize a Xml document:
typedef struct xmllist
{
std::string Name;
int Param;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(Name);
ar & BOOST_SERIALIZATION_NVP(Param);
}
} XMLLIST;
void XmlWrite()
{
std::ofstream ofs("xmlfile.xml");
assert(ofs.good());
boost::archive::xml_oarchive oa(ofs);
XMLLIST xmllist;
xmllist.Name = "Name";
xmllist.Param = 1;
oa << BOOST_SERIALIZATION_NVP(xmllist);
}
boost::archive::xml_oarchive oa(ofs) is giving me Run-Time Check Failure #2 - Stack around the variable 'oa' was corrupted.
I'm using Microsoft Visual Studio 2010 and boost_1_56_0.
Can someone please help me in this issue?
My opinion that the stack corruption happens not in the provided code but somewhere else. The slightly modified code, which I provided below, works without any error under MSVC++ 2013 and Boost 1.57. Also it works fine on coliru.
#include <string>
#include <sstream>
#include <iostream>
#include <ostream>
#include <cassert>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/access.hpp>
struct CXMLList {
std::string Name;
int Param;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(Name);
ar & BOOST_SERIALIZATION_NVP(Param);
}
};
int main(int argc, char* argv[]) {
std::ostringstream ofs;
boost::archive::xml_oarchive oa(ofs);
CXMLList xmllist;
xmllist.Name = "Name";
xmllist.Param = 1;
oa << BOOST_SERIALIZATION_NVP(xmllist);
std::cout << "XML is:" << std::endl;
std::cout << ofs.str() << std::endl;
return 0;
}

Error serializing an abstract class with boost

I'm trying to serialize my data structures in order to write them to a tcp socket.
So far I found that my problem is the serialization. I even tried to use
BOOST_SERIALIZATION_ASSUME_ABSTRACT(T)
but I can't find any working example similar to my program and how to implement it correctly.
Here are some of the links that I have visited:
http://programmers-blog.com/category/c-c
http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/tutorial.html#simplecase
http://en.highscore.de/cpp/boost/serialization.html#serialization_class_hierarchies
My data structures are a little more complicated then this one but let's assume that I have the following structure
Coordinate.h
#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
class Coordinate {
public:
Coordinate() {}
Coordinate(int c) : c(c) {}
int get(void) { return c; }
std::string toString(void);
private:
int c;
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive &ar, const unsigned int version) {
ar & this->c;
}
};
Move.h
class Coordinate;
#include "Coordinate.h"
#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
class Move {
public:
Move() {}
~Move() {}
Coordinate* getCoordinate(void) {return this->destination; }
virtual bool isJump(void) = 0;
protected:
Coordinate *destination;
private:
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive &ar, const unsigned int version) {
ar & this->destination;
}
};
MoveNormal.h
class Coordinate;
#include "Move.h"
#include "Coordinate.h"
#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
class MoveNormal : public Move {
public:
MoveNormal() {}
MoveNormal(Coordinate *destination) { this->destination = destination; }
~MoveNormal() {}
virtual bool isJump(void);
private:
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive &ar, const unsigned int version) {
ar & boost::serialization::base_object<Move>(*this);
}
};
The virtual methods are defined in here.
MoveNormal.cpp
#include "MoveNormal.h"
bool MoveNormal::isJump(void) {
return false;
}
My main.cpp looks like this:
#include "Coordinate.h"
#include "Move.h"
#include "MoveNormal.h"
#include <fstream>
#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
int main(int argc, char *argv[]) {
Coordinate *c = new Coordinate(10);
// This runs OK
/*
{
std::ofstream ofs("f.txt");
boost::archive::text_oarchive oa(ofs);
oa << c;
}
Coordinate *d;
{
std::ifstream ifs("f.txt");
boost::archive::text_iarchive ia(ifs);
ia >> d;
}
std::cout << "c.get(): " << c->get() << std::endl;
std::cout << "d.get(): " << d->get() << std::endl;
*/
// This is where I get my error
Move *m = new MoveNormal(c);
{
std::ofstream ofs("f.txt");
boost::archive::text_oarchive oa(ofs);
oa << m; // Line where the error occurs
}
return 0;
}
But when I run the program I get the following error:
Unhandled exception at 0x76dbb9bc in Test.exe: Microsoft C++ exception: boost::archive::archive_exception at memory location 0x001df078..
I'm using VS2010, and Boost 1.48.0.
This is a little bit weird but I'm going to answer my own question. I just figured out how to make my example above work.
Here it goes the solution. Everytime we need to serialize a class that inherits attributes from another class we need to use the macro:
BOOST_CLASS_EXPORT(T)
According to the boost serialization doc
BOOST_CLASS_EXPORT in the same source module that includes any of the archive class headers will instantiate code required to serialize polymorphic pointers of the indicated type to the all those archive classes. If no archive class headers are included, then no code will be instantiated.
Note that the implemenation of this functionality requires that the BOOST_CLASS_EXPORT macro appear after and the inclusion of any archive class headers for which code is to be instantiated.
So in my case my main.cpp file is now:
#include <fstream>
#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
#include <boost\serialization\export.hpp>
#include "Coordinate.h"
#include "Move.h"
#include "MoveNormal.h"
BOOST_CLASS_EXPORT(MoveNormal)
int main(int argc, char *argv[]) {
Coordinate *c = new Coordinate(150);
Move *m = new MoveNormal(c);
std::cout << "m.getDestination().get(): " << m->getDestination()->get() << std::endl;
{
std::ofstream ofs("f.txt");
boost::archive::text_oarchive oa(ofs);
oa << m;
}
Move *n;
{
std::ifstream ifs("f.txt");
boost::archive::text_iarchive ia(ifs);
ia >> n;
}
std::cout << "n.getDestination().get(): " << n->getDestination()->get() << std::endl;
return 0;
}
Just make sure that you include all the boost archives you need before you use the export MACRO.
To finish my project besides the serialization I need to write them to a tcp socket using boost::asio.
So let's assume that I have a connection header like this one and that now I have another class called MoveJump defined in my MoveJump.h
#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
#include "Coordinate.h"
#include "Move.h"
class MoveJump : public Move {
public:
MoveJump() {}
MoveJump(Coordinate *c) { this->destinatio = c; }
~MoveJump() {}
virtual bool isJump(void);
private:
friend class boost::serialization::access;
template<typename Archive>
void serializize(Archive &ar, const unsigned int version) {
ar & boost::serialization::base_object<Move>(*this);
}
};
Now to serialize these structures my main look like this
#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
#include <boost\serialization\export.hpp>
#include <fstream>
#include "Coordinate.h"
#include "Move.h"
// And now we register all the possible Moves
#include "MoveNormal.h"
BOOST_CLASS_EXPORT(MoveNormal)
#include "MoveJump.h"
BOOST_CLASS_EXPORT(MoveJump)
int main(int argc, char *argv[]) {
Coordinate *c = new Coordinate(10);
Move *m = new MoveNormal(c);
Coordinate *d = new Coordinate(15);
Move *j = new MoveJump(d);
{
std::ofstream ofs("m.txt");
boost::archive::text_oarchive oa(ofs);
oa << m;
}
{
std::ofstream ofs("j.txt");
boost::archive::text_oarchive oa(ofs);
oa << j;
}
}
The trick is to register the classes that will be serialized when we have the pointer to the base class.
If inside my Move.h I have more pointers to other base classes, which I do in my project, we need to include in the main all the headers and register all the possible classes that expand the base class.
I hope this helps someone who might have similar problems in the future.
Feel free to present new possible solutions.
Thanks
General speaking, you can simply use BOOST_CLASS_EXPORT to register all the classes, or you can use BOOST_SERIALIZATION_ASSUME_ABSTRACT for the super class, and use member function register_type of "archive" together. see : How to serialize derived template classes with Boost.serialize? for details.(sorry for my poor english:))

Compilation error with boost serialization

I created a small sample for testing the boost serialization library, but I have a compilation problem.
First of all, here's the code:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <boost/filesystem/operations.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/version.hpp>
std::vector<uint8_t> buf;
class MyClass
{
public:
MyClass(){};
virtual ~MyClass(){};
int assetStatus;
friend class boost::serialization::access;
template<typename Archive> void serialize(
Archive & ar,
const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(assetStatus);
}
std::string ToString()
{
std::string toret;
toret += " assetStatus: " + assetStatus;
return toret;
}
};
int main()
{
MyClass a, b;
a.assetStatus = 10;
std::cout << a.ToString();
boost::archive::xml_oarchive ooxml(std::ofstream(dbPath));
ooxml << BOOST_SERIALIZATION_NVP(a); // error here
MyClass d;
boost::archive::xml_iarchive iixml(std::ifstream(dbPath));
iixml >> BOOST_SERIALIZATION_NVP(d); // error here
std::cout << d.ToString();
}
I get a compilation error at the lines:
ooxml << BOOST_SERIALIZATION_NVP(a);
and
iixml >> BOOST_SERIALIZATION_NVP(d);
The error is:
no match for operator>> in 'iixml >> boost::serialization::make_nvp(const char*, T&) [with T=MyClass(((MyClass&)(&d)))]'
Do you have any idea regarding the meaning of this?
It looks like dbPath is not defined. Additionally, the declaration of ooxml/iixml appears incorrect.
Try modifying your code to do the following:
...
const char * dbPath = "file.xml"
std::ofstream ofs(dbPath);
boost::archive::xml_oarchive ooxml(ofs);
ooxml << BOOST_SERIALIZATION_NVP(a);
std::ifstream ifs(dbPath);
boost::archive::xml_iarchive iixml(ofs);
iixml >> BOOST_SERIALIZATION_NVP(d);
I think NVP (name value pair) is not supported for reading (i.e. with iixml), either use & (instead of >>) or iixml >> d;