I am trying to store a User object and then read the stored object using the boost serialization library and VS2015 community. I followed the tutorial here. Currently the read/write object to file works just fine; however, after reading the object back in I cannot access any of the objects members (i.e. username and pw_hash). Is there something I am missing? I have seen tons of questions how to write/read the object using the library but none that show anyone accessing the objects members after reading the object from file.
Class:
#ifndef USER_H
#define USER_H
#include <fstream>
#include <string>
#include <boost\serialization\string.hpp>
#include <boost\archive\text_oarchive.hpp>
#include <boost\archive\text_iarchive.hpp>
#include "Hash.h"
class User
{
public:
User();
User(std::string & name, std::string & pwd);
~User();
private:
std::string pw_hash;
std::string username;
inline std::string get_username();
inline void set_username(const std::string & name);
inline std::string get_PwHash();
inline void set_PwHash(const std::string & hash);
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & username;
ar & pw_hash;
}
};
#endif
Below is where I encounter my problem. After the object is read from memory, VS2015 underlines test2.get_username() saying it is inaccessible.
Implementation:
#include "User.h"
int main(int argc, char *argv[])
{
User test("User1", "Password");
std::cout << test.get_username() << std::endl;
{
std::ofstream ofs("User1");
boost::archive::text_oarchive oa(ofs);
oa << test;
}
User test2();
{
std::ifstream ifs(username);
boost::archive::text_iarchive ia(ifs);
ia >> test2;
//error
std::cout << test2.get_username() << std::endl;
}
return 0;
}
Related
I am on my second attempt to setup polymorphic serialization using the boost library. I am using this as a learning experience, but I may be a little in over my head and I am considering going back to coding the serialization myself rather than boost. Or switch to learning the vistor message Sehe showed me in a previous post.
The issue I am seeing is "unregistered void cast"
I am using shared library linking for the boost serialization library
aTodo.h:
#ifndef ATODO_H
#define ATODO_H
#include <boost/serialization/export.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
class aTodo{
public:
static const unsigned _Type=0x00;
virtual ~aTodo(){};
virtual void Do()=0;
virtual unsigned getInitType(){return _Type;};
private:
friend class boost::serialization::access;
template <class Ar> void serialize(Ar &, unsigned){};
};
#endif
todoExec.h:
#ifndef ATODOEXEC_H
#define ATODOEXEC_H
#include "aTodo.h"
class todoExec : public aTodo{
public:
static const unsigned _TYPE= 0x01;
todoExec(std::string const & command=""):_command(command){};
virtual unsigned getInitType(){return _TYPE;};
virtual void Do(){std::cout << "foo:" << getCommand() << std::endl;};
std::string getCommand() const {return _command;};
protected:
private:
friend class boost::serialization::access;
template <class Archive> void serilize(Archive & ar, unsigned){
boost::serialization::void_cast_register<todoExec,aTodo>();
boost::serialization::base_object<aTodo>(*this);
ar& _command;
}
std::string _command;
};
#endif
todoFactory.h:
#ifndef TODOFACTORY_H
#define TODOFACTORY_H
#include "todoExec.h"
#include <memory>
class todoFactory{
todoFactory()=default;
public:
static std::unique_ptr<todoFactory> create(){return std::move(std::unique_ptr<todoFactory>(new todoFactory));};
//save
static std::string save(std::unique_ptr<aTodo> &todoIn){
std::string out;
{
boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>>os(out);
boost::archive::text_oarchive archive(os);
archive << todoIn;
}
return out;
}
static std::unique_ptr<aTodo> load(std::string const &s ){
std::unique_ptr<aTodo> p;
{
boost::iostreams::stream<boost::iostreams::array_source> is(boost::iostreams::array_source{s.data(),s.size()});
boost::archive::text_iarchive archive(is);
archive >> p;
}
return std::move(p);
}
std::unique_ptr<aTodo> createExec(std::string command) {return std::unique_ptr<aTodo>(new todoExec(command));};
};
#endif
client.cpp
#include <string>
#include <iostream>
#include "todoFactory.h"
BOOST_SERIALIZATION_ASSUME_ABSTRACT(aTodo)
BOOST_CLASS_EXPORT(todoExec)
#include <memory>
int main(void)
{
char mtype=0x01;
std::string dataToSend = "ls -al /home/ajonen";
auto tmpTodoFactory=todoFactory::create(); //create factory
auto anExecTodo=tmpTodoFactory->createExec(dataToSend); //create ExecTodo from factory
std::string toSend= tmpTodoFactory->save(anExecTodo);
return 0;
}
The error I get is:
terminate called after throwing an instance of 'boost::archive::archive_exception'
what(): unregistered void cast 8todoExec<-5aTodo
Aborted
In class todoExec you've got a typo - is: serilize, should be: serialize; therefore the cast is not registered.
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;
}
I have a class Cl with public member
static std::ofstream &_rout;
In main file
ofstream out("output.txt");
ofstream& Cl::_rout(out);
But I have a compilation error: illegal definition or redefinition.
How can I correct it?
Try this.
Logger.h
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
class Logger{
public:
static void open( const string & logFile);
static void close();
// write message
static void write( const string & message);
private:
Logger();
ofstream fileStream;
//Logger instance (singleton)
static Logger instance;
};
Logger.cpp
#include "Logger.h"
Logger Logger::instance;
Logger::Logger(){}
void Logger::open( const string& logFile){
instance.fileStream.open(logFile.c_str());
}
void Logger::close(){
instance.fileStream.close();
}
void Logger::write(const string& message){
ostream& stream = instance.fileStream ;
stream << message<< endl;
}
main.cpp
#include "Salida/Logger.h"
int main(){
Logger::open(path);
Logger::write("text");
Logger::close();
return 0;
}
You can only set the reference at the static/global scope
#include<CL.h>
ofstream& Cl::_rout(out);
int main() {
// ...
}
It is not possible to re-set a reference after it was declared (and initialized). You could achieve what you are after by using pointers instead of references:
class Cl {
static std::ofstream* _rout;
};
std::ofstream* CL::_rout = NULL;
int main() {
ofstream out("output.txt");
Cl::_rout = &out;
}
Note that the pointer will be valid only until out goes out of scope. If this is an issue, allocate the memory dynamically:
ofstream* out = new ofstream("output.txt");
Cl::_rout = out;
And don't forget to delete it when you no longer need the object to avoid memory leaks
Well, you could use the following approach:
#include <fstream>
class CI
{
public:
static std::ofstream &_rout;
};
static std::ofstream out("output.txt");
std::ofstream& CI::_rout = out;
int main()
{
}
The problem with this, however, is that the name of the output file is fixed (hard-coded into the program).
I suggest that you use a pointer instead of a reference:
#include <cstddef>
#include <fstream>
class CI
{
public:
static std::ofstream *_rout;
};
std::ofstream* CI::_rout = NULL;
int main()
{
const char *output_file = "output.txt";
std::ofstream out(output_file);
CI::_rout = &out;
}
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:))
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;