How to serialize/deserialize derived class inheriting base class without default constructor?
Please offer serializing boost functions for the following classes
struct Base
{
Base(int b) : b(b) {}
const int b;
}
struct Derived : public Base
{
Derived(float d, int b) : Base(b), d(d) {}
const float d;
}
Your use-case straddles two of the "special considerations" documented by Boost Serialization:
Note that I'm going to assume you want dynamic polymorphism, and to get this you need at least a virtual destructor. If you don't you will end up with Undefined Behaviour.
Combining the two for your example:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/export.hpp>
#include <iostream>
struct Base {
Base(int b) : b(b) {}
virtual ~Base() = default;
const int b;
};
namespace boost::serialization {
template <typename Ar> inline void serialize(Ar&, Base&, unsigned) {}
template <typename Ar>
inline void save_construct_data(Ar& ar, Base const* p, unsigned) {
// save data required to construct instance
ar << p->b;
}
template <typename Ar>
inline void load_construct_data(Ar& ar, Base* p, unsigned) {
int attribute;
ar >> attribute;
// invoke inplace constructor to initialize instance
::new (p) Base(attribute);
}
} // namespace boost::serialization
struct Derived : public Base {
Derived(float d, int b) : Base(b), d(d) {}
const float d;
};
BOOST_CLASS_EXPORT(Base)
BOOST_CLASS_EXPORT(Derived)
namespace boost::serialization {
template <typename Ar> inline void serialize(Ar& ar, Derived& d, unsigned) {
ar & boost::serialization::base_object<Base>(d);
}
template <typename Ar>
inline void save_construct_data(Ar& ar, Derived const* p, unsigned) {
// save data required to construct instance
ar & p->b & p->d;
}
template <typename Ar>
inline void load_construct_data(Ar& ar, Derived* p, unsigned) {
int b;
float d;
ar & b & d;
// invoke inplace constructor to initialize instance
::new (p) Derived(d, b);
}
} // namespace boost::serialization
std::string save(Base* b) {
std::ostringstream oss;
{
boost::archive::text_oarchive oa(oss);
oa << b;
}
return oss.str();
}
Base* load(std::string txt) {
std::istringstream iss(std::move(txt));
boost::archive::text_iarchive ia(iss);
Base* b = nullptr;
ia >> b;
return b;
}
int main() {
for (Base* object :
{
new Base(-99),
static_cast<Base*>(new Derived(3.14, 42)),
}) //
{
std::cout << "----\n";
Base* roundtrip = load(save(object));
delete object;
std::cout << "roundtrip: b=" << roundtrip->b;
if (auto* as_derived = dynamic_cast<Derived const*>(roundtrip)) {
std::cout << ", d=" << as_derived->d;
}
std::cout << "\n";
delete roundtrip;
}
}
Prints
----
roundtrip: b=-99
----
roundtrip: b=42, d=3.14
Of course, don't use raw new/delete:
unique_ptr
Live On Colirushared_ptr
(note the dynamic_pointer_cast
) Live On Coliru