1
votes

I'm trying to serialize and deserialize a polymorphic class (with virtual inheritance) using Cereal 1.1.2. I get an 'Access violation - no RTTI data!' exception when I try to downcast it to the derived class after deserializing it. It works fine when I use normal inheritance instead of virtual inheritance. I have already enabled RTTI (/GR) in the project settings in Visual Studio 2013 Community Edition. Here's my code:

class Boogie
{
    friend class cereal::access;
    virtual void virtualFunction() {}
    int boogieInt = 3;
    template<class Archive>
    void serialize(Archive & archive)
    {
        archive(boogieInt);
    }
};

class Booga : virtual public Boogie
{
    friend class cereal::access;
public:
    void virtualFunction() {}
    int boogaInt = 2;
    template<class Archive>
    void serialize(Archive & archive)
    {
        archive(cereal::virtual_base_class<Boogie>(this), boogaInt);
    }
};

CEREAL_REGISTER_TYPE(Booga);

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        {
            std::shared_ptr<Boogie> boogie = std::make_shared<Booga>();
            std::ofstream ofs("Booga.txt");
            cereal::BinaryOutputArchive archive(ofs);
            archive(boogie);
            ofs.close();
        }

        std::shared_ptr<Boogie> deBoogie;
        std::ifstream ifs("Booga.txt");
        cereal::BinaryInputArchive iarchive(ifs);
        iarchive(deBoogie);

        std::shared_ptr<Booga> outBooga = std::dynamic_pointer_cast<Booga>(deBoogie);

        std::cout << outBooga->boogaInt << std::endl;

        std::cin.get();
    }
    catch (std::exception e)
    {
        std::cout << "EXCEPTION" << std::endl;
        std::cout << e.what() << std::endl;
    }
    return 0;
}
1
For me your example just segfaults, since it cannot convert deserialized smart pointer to child class... - ForEveR
A quick comment - you should always make sure the archives are destroyed before you do anything with the results. They will be destroyed when they go out of scope. See the documentation for more details. - Azoth

1 Answers

0
votes

Your problem is that you are saving and loading different types - your load code should mirror your save code.

Also note that you do not need to be using virtual inheritance here since you only derive from a single parent class - see here for more info on that). In addition please see my comment to your post about how to properly use archives in an RAII manner.

Your output could be specified as:

std::shared_ptr<Boogie> data = std::make_shared<Booga>();
archive( data ); // data is actually a Booga but we hold it in a Boogie ptr

Note that I assigned into a Boogie object even though I allocated a Booga pointer - this is basically the entire point of polymorphism and unless you need to do this, don't use polymorphism.

Now when we do the load, we load into the same type that we serialized:

std::shared_ptr<Boogie> data;
archive( data ); // data is actually a Booga object because of polymorphism

Just ensure that the types of the variables you actually pass to the archive are identical, regardless of what they actually are due to polymorphism.