0

I have a class A, which contains the object of class B and I want to serialize it. The problem is, the class C inherits from B, so A can contain an object of either B or C. How can I efficiently implement the serialization with Boost?

My attempt is below, but I'm getting the error when trying to serialize A with C object, while with B it works correctly. Do you know, what am I doing wrong?

I've found some information about class-hierarchy objects serialization here, but it requires an explicit registration of the type in text_iarchive, whereas I need it to be registered in the A class because I'm not directly serializing B objects.


My attempt:

#include <fstream>
#include <iostream>
#include <vector>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

class B {
    friend class boost::serialization::access;

private:
    template<class Archive>
    void save(Archive & ar, const unsigned int version) const {
        ar & this->v->size();
        for(int i = 0; i < this->v->size(); i++) {
            ar & (*(this->v))[i];
        }
    };

    template<class Archive>
    void load(Archive & ar, const unsigned int version) {
        size_t size;
        int tmp;
        ar & size;

        this->v = new std::vector<int>(size);
        for(int i = 0; i < size; i++) {
            ar & tmp;
            (*this->v)[i] = tmp;
        }
    }

    BOOST_SERIALIZATION_SPLIT_MEMBER()

protected:
    std::vector<int>* v;

public:
    B();
    B(std::vector<int>* v);
    virtual void print_vals();
};

B::B() {
    this->v = nullptr;
}

B::B(std::vector<int>* v) {
    this->v = v;
}

void B::print_vals() {
    for(auto e : *(this->v)) {
        std::cout << e << std::endl;
    }
}

class C : public B {
    friend class boost::serialization::access;
private:
    int num2;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version){
        ar & boost::serialization::base_object<B>(*this);
        ar & num2;
    };

public:
    void print_vals() override {
        for(auto e : *(this->v)) {
            std::cout << e << std::endl;
        }
        std::cout << this->num2 << std::endl;
    }

    C();
    C(int num2, std::vector<int>* v);

};

C::C() {
    this->num2 = -1;
    this->v = nullptr;
}

C::C(int num2, std::vector<int> *v) {
    this->num2 = num2;
    this->v = v;
}

class A {
    friend class boost::serialization::access;

private:
    int num;

    B* b_obj;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version){
        ar & num;
        ar & b_obj;
    };

public:
    A();
    A(int num, B* b);

    void print_vals();
};

A::A() {
    this->num = -1;
    this->b_obj = nullptr;
}

A::A(int num, B* b) {
    this->num = num;
    this->b_obj = b;
}

void A::print_vals() {
    std::cout << this->num << std::endl;
    this->b_obj->print_vals();
}


int main() {
    std::vector<int> v{1,2,3};

    B b = B(&v);

    A a(4, &b);
    std::cout << "a:" << std::endl;
    a.print_vals();

    std::ofstream ofs("a.txt");
    {
        boost::archive::text_oarchive oa(ofs);
        oa << a;
        ofs.close();
    }

    A a2;
    std::ifstream ifs("a.txt");
    {
        boost::archive::text_iarchive ia(ifs);
        ia >> a2;
        ifs.close();
    }
    std::cout << "a2:" << std::endl;
    a2.print_vals();

    C c(2, &v);
    A a3(6, &c);
    std::cout << "a3:" << std::endl;
    a3.print_vals();

    std::ofstream ofs2("a3.txt");
    {
        boost::archive::text_oarchive oa(ofs2);
        oa << a3;
        ofs.close();
    }

    A a4;
    std::ifstream ifs2("a3.txt");
    {
        boost::archive::text_iarchive ia(ifs2);
        ia >> a4;
        ifs.close();
    }
    std::cout << "a4:" << std::endl;
    a4.print_vals();


}

OUTPUT:

a:
4
1
2
3
a2:
4
1
2
3
a3:
6
1
2
3
2
terminate called after throwing an instance of 'boost::archive::archive_exception'
  what():  unregistered class - derived class not registered or exported
Signal: SIGABRT (Aborted)
Eenoku
  • 2,741
  • 4
  • 32
  • 64
  • May be solved in https://stackoverflow.com/questions/4432019/boost-serialization-exception-unregistered-class-serializing-polymorphic-base – leiyc Aug 12 '18 at 13:24
  • @leiyc It's not, the question you posted asks about abstract class, but my `B` class is instantiable. – Eenoku Aug 12 '18 at 13:29
  • 1
    how about this? https://stackoverflow.com/questions/33365093/boost-serialize-child-class – miradham Aug 12 '18 at 14:12
  • @Eenoku, works with the hint of **miradham**. See http://coliru.stacked-crooked.com/a/57c0f58270c70571 – leiyc Aug 12 '18 at 15:01
  • @miradham Could you, please, write a full answer, so I could accept it? – Eenoku Aug 12 '18 at 18:53

1 Answers1

1

It turns that you have missed BOOST_CLASS_EXPORTfor derived class, i.e.

BOOST_CLASS_EXPORT(C)

Boost serialization cannot serialize pointer to derived object correctly without this macro.

You can find full working code here

miradham
  • 2,285
  • 16
  • 26