How to serialize/deserialize object with boost (c++11) when object contains
vector<map<u_int64_t, Student*>*>* students;
like:
class YearContainer{
public:
vector<map<u_int64_t, Student*>*>* students;
};
where class Student has serialize method like
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & name;
// ....
}
How to deserialize and create all on heap ?
This looks like it uses the Boost.Serialization library. I don't really see a more specific question here.
Related
I have Players class and it has some variables
class Players
{
private:
friend class boost::serialization::access;
template <class Ar>
void serialize(Ar &ar, unsigned)
{
ar &username &password;
}
public:
std::string username = "", password = "", email = "";
};
I just want to serialize username and password. I dont want to add email too. I'm getting error after trying to deserialize it.
Your code seems correct.
Remember that you cannot deserialize an archive that you created with an old version of the serialization routines.
If that is the case, as a very primitive workaround you can do this below, or learn how to deal with archive versions.
template <class Ar>
void serialize(Ar &ar, unsigned)
{
std::string dummy_email = "";
ar &username &password & dummy_email;
}
I loaded multiple data into boost::archive::text_oarchive, now I need to extract the data.
But because the archive contains multiple records, I would need an iterator.
something like
//input archive
boost::archive::text_iarchive iarch(ifs);
//read until the end of file
while (!iarch.eof()){
//read current value
iarch >> temp;
...//do something with temp
}
is there any standard way to iterate over elements of the archive?
I found only iarchive.iterator_type, but is it what I need and how do I use it?
The iterator type you are looking at actually comes from
class shared_ptr_helper {
...
typedef std::set<
boost::shared_ptr<const void>,
collection_type_compare
> collection_type;
typedef collection_type::const_iterator iterator_type;
which is used during the load of the archive rather than being an iterator for external use I think.
If you look at the link http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/index.html under tutorial -> STL Collection you will see the following example:
#include <boost/serialization/list.hpp>
class bus_route
{
friend class boost::serialization::access;
std::list<bus_stop *> stops;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & stops;
}
public:
bus_route(){}
};
If that isn't quite what you need then you would probably need to look at overriding load and save as per http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/tutorial.html#splitting
and adding handling as required.
As far as I understand, there is no serialization (boost::serialization, actually) support for boost::any placeholder.
Does someone know if there is a way to serialize a custom boost::any entity?
The problem here is obvious: boost::any uses template-based placeholders to store objects and typeid to check if boost::any_cast is appropriate.
So, there is a custom abstract superclass placeholder and custom template-based derived classes, which are created the following way:
template <T> custom_placeholder : public placeholder {
virtual std::type_info type() const { return typeid(T); }
virtual ...
};
Obviously, this brings some troubles when even thinking about serializing this stuff. Maybe someone knows some trick to make such kind of serialization (and of course, proper deserialization)?
Thank you
If you want to stick with boost::any i am not sure but you can write your own "boost::any". I'm using this code for proxy methods to pass the parameters.
#include <iostream>
#include <boost\smart_ptr\scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>
#include <sstream>
class my_placeholder
{
public:
virtual ~my_placeholder(){}
my_placeholder(){}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
//ar & boost::serialization::base_object<bus_stop>(*this);
//ar & m_placeholder;
}
};
template<typename T>
class my_derivedplaceholder:
public my_placeholder
{
public:
my_derivedplaceholder()
{
}
my_derivedplaceholder(T &value)
{
m_value=value;
}
T m_value;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
ar & boost::serialization::base_object<my_placeholder>(*this);
ar & m_value;
}
};
BOOST_CLASS_EXPORT_GUID(my_derivedplaceholder<int>, "p<int>");
class my_any
{
public:
my_any()
{
}
template<typename T>
my_any(const T &value)
{
m_placeholder.reset(new my_derivedplaceholder<T>(const_cast<T&>(value)));
}
template<typename T>
void operator=(const T &value)
{
m_placeholder.reset(new my_derivedplaceholder<T>(const_cast<T&>(value)));
}
protected:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
//ar & boost::serialization::base_object<bus_stop>(*this);
ar & m_placeholder;
}
template<typename T>
friend T my_anycast(my_any &val);
boost::shared_ptr<my_placeholder> m_placeholder;
};
template<typename T>
T my_anycast(my_any &val)
{
boost::shared_ptr<my_derivedplaceholder<T>> concrete=boost::dynamic_pointer_cast<my_derivedplaceholder<T>>(val.m_placeholder);
if (concrete.get()==NULL)
throw std::invalid_argument("Not convertible");
return concrete->m_value;
}
void main()
{
my_any m=10;
int a=my_anycast<int>(m);
std::cout << a << std::endl;
std::stringstream ss,ss2;
boost::archive::text_oarchive oa(ss);
oa << m;
boost::archive::text_iarchive ia(ss);
my_any m2;
ia >> m2;
std::cout << my_anycast<int>(m2) << std::endl;
}
It is not possible at all, at least for arbitrary types. Note that maybe you could serialize using some tricky code (like finding the size of the elements contained in the any), but the any code relies on the compiler statically putting the any type_code and the proper types inside the placeholder. You surely cannot do that in deserialization in C++, as the type that you'd get from the deserialization is not known at compile time (as required by the newly formed boost::any).
The best solution is to build some kind of specialized any type for the exact types of elements you're going to serialize. Then, you can have special cases for the actual type of element being deserialized, but note that each element type serialization/deserialization has to be phisically written as static C++ code.
PD. Some others suggested using boost::variant as a representation of this specialized type holding the exact types you're going to serialize. You need a way of discerning the exact type on deserialization, though (maybe assigning identifiers to types in the variant).
Assuming you have to use boost::any and you cannot switch to variant, a map<type_info const*, string(*)(any)> based solution could get you done.
You have to initialize at runtime such a map with all the types you plan to use. Of course, you can use something along the lines of
template <typename T>
struct any_serializer
{
static string perform(any a)
{
T const& x = any_cast<T const&>(a);
stringstream out;
out << x;
return out.str();
}
};
and populate the map with addresses of any_serializer<T>::perform under the key &typeid(T). You can specialize the class any_serializer and use some (ugly) macros to populate the map.
More difficult is of course the deserialization. I haven't had a look at boost::lexical_cast for a while, perhaps it can provide some help. I am afraid that this is totally problem-dependant. However, you only need one function, which takes a string and returns one any. You may also want to prepend your output string with a custom type identifier.
There is no need to create new class. Try to use xany https://sourceforge.net/projects/extendableany/?source=directory
xany class allows to add new methods to any's existing functionality. By the way there is a example in documentation which does exactly what you want.
Using boost::serialization, what's the "best" way to serialize an object that contains cached, derived values in mutable members?
class Example
{
public:
Example(float n) :
num(n),
sqrt_num(-1.0)
{}
// compute and cache sqrt on first read
float get_sqrt() const
{
if(sqrt_num < 0)
sqrt_num = sqrt(num);
return sqrt_num;
}
template <class Archive>
void serialize(Archive& ar, unsigned int version)
{ ... }
private:
float num;
mutable float sqrt_num;
};
I'd like to avoid splitting serialize() into separate save() and load() methods, for maintenance reasons.
One suboptimal implementation of serialize:
template <class Archive>
void serialize(Archive& ar, unsigned int version)
{
ar & num;
sqrt_num = -1.0;
}
This handles the deserialization case, but in the serialization case, the cached value is killed and must be recomputed.
What is the best practice in this case?
Splitting your saving and loading methods doesn't mean you have to maintain two copies of your serialization code. You can split them and then join them back again with a common function.
private:
friend class boost::serialization::access;
BOOST_SERIALIZATION_SPLIT_MEMBER()
template <class Archive>
void save(Archive& ar, const unsigned int version) const {
const_cast<Example*>(this)->common_serialize(ar, version);
}
template <class Archive>
void load(Archive& ar, const unsigned int version) {
common_serialize(ar, version);
sqrt_num = -1;
}
template <class Archive>
void common_serialize(Archive& ar, const unsigned int version) {
ar & num;
}
You probably noticed the const_cast. That's an unfortunate caveat to this idea. Although the serialize member function is non-const for saving operations, the save member function needs to be const. As long as the object you're serializing wasn't originally declared const, though, it's safe to cast it away as shown above. The documentation briefly mentions the need to cast for const members; this is similar.
With the changes above, your code will correctly print "2" for both ex1 and ex2, and you only have to maintain one copy of the serialization code. The load code only contains code specific to re-initializing the object's internal cache; the save function doesn't touch the cache.
You can check the Archive::is_loading field, and load cached values if it's true.
template <class Archive>
void serialize(Archive& ar, unsigned int version)
{
ar & num;
if(Archive::is_loading::value == true)
sqrt_num = -1.0;
}
I have a complex network of objects connected with QSharedPointers and QWeakPointers. Is there a simple way to save/load them with Boost.Serialization? So far I have this:
namespace boost {
namespace serialization {
template<class Archive, class T>
void save(Archive& ar, QSharedPointer<T> const& ptr, unsigned version) {
T* sharedPointer = ptr.data();
ar & BOOST_SERIALIZATION_NVP(sharedPointer);
}
template<class Archive, class T>
void load(Archive& ar, QSharedPointer<T>& ptr, unsigned version) {
T* sharedPointer = 0;
ar & BOOST_SERIALIZATION_NVP(sharedPointer);
ptr = QSharedPointer<T>(sharedPointer);
}
template<class Archive, class T>
void save(Archive& ar, QWeakPointer<T> const& ptr, unsigned version) {
T* weakPointer = ptr.toStrongRef().data();
ar & BOOST_SERIALIZATION_NVP(weakPointer);
}
template<class Archive, class T>
void load(Archive& ar, QWeakPointer<T>& ptr, unsigned version) {
T* weakPointer = 0;
ar & BOOST_SERIALIZATION_NVP(weakPointer);
ptr = QSharedPointer<T>(weakPointer);
}
}
}
This is not working because the shared pointers are always constructed from raw pointers so they all think the reference count is 1. It also immediately frees weak pointers.
With some effort I can convert the classes to use boost::shared_ptr and boost::weak_ptr. Will that do any good?
The question is what do you really want to achieve by serializing pointers? What is your expected output? Note that pointers point to a place in memory -- several may point to the same place in memory.
Serializing the address won't work. You can't just write down the exact memory address, because there's no way to guarantee that objects on the next run will be able to take the same space (another program may have already reserved that place).
Serializing the pointed object in each place where we have a pointer wont work:
This would be a lot more data that we'd need to serialize
If we had weak pointers creating a circular dependency we wouldn't be able to stop and retrieve that connection later.
There is no way to merge the same objects into one when deserializing
Now that you think about it, you can try the official answer of boost::serialization:
boost::serialization on shared_ptr
boost::serialization on shared_ptr 2