CEREAL_REGISTER_TYPE in shared libraries

772 views
Skip to first unread message

Hans Kirchner

unread,
Jun 22, 2015, 5:45:43 AM6/22/15
to cere...@googlegroups.com
Hi all,

I got a problem with polymorphic classes and shared libraries.
Everything gets compiled with CMake 2.8.12.2 and clang++ 3.4 on Ubuntu 14.04 x86_64.
I have a shared library street_enviroment with the base class EnvironmentObject:

CEREAL_FORCE_DYNAMIC_INIT(street_environment)

class EnvironmentObject {
private:
    std::string m_name;
public:
    virtual ~EnvironmentObject() {}

    template <class Archive>
    void serialize( Archive & ar ) {
        ar(m_name);
    }
};

My derived class RoadLane is implemented like this:
class RoadLane:public lms::math::polyLine2f,public EnvironmentObject {
        RoadLaneType m_type;
    public:
        std::vector<double> polarDarstellung; //TODO english name :)
        float polarPartLength;

        template <class Archive>
        void serialize( Archive & archive) {
            archive (cereal::base_class<lms::math::polyLine2f>(this),
                    cereal::base_class<street_environment::EnvironmentObject>(this),
                     m_type, polarDarstellung, polarPartLength);
        }
};

There is also a CPP file that is compiled into the shared library with this content:
CEREAL_REGISTER_TYPE(RoadLane)
CEREAL_REGISTER_DYNAMIC_INIT(street_environment)

Then I've written a googletest executable with this test case:
TEST(Serialization, EnvironmentObject) {
    ASSERT_GT(output_serializers<EnvironmentObject>::value, 0);
    std::stringstream ss;
    {
        cereal::PortableBinaryOutputArchive oarchive(ss);
        std::shared_ptr<EnvironmentObject> ptr = std::make_shared<RoadLane>();
        ptr->name("my lane");
        //ptr->type(RoadLaneType::MIDDLE);
        oarchive(ptr);
    }
    {
        cereal::PortableBinaryInputArchive iarchive(ss);
        std::shared_ptr<EnvironmentObject> obj;
        iarchive(obj);
        RoadLane *lane = dynamic_cast<RoadLane*>(obj.get());
        ASSERT_NE(nullptr, lane);
        ASSERT_EQ(std::string("my lane"), lane->name());
    }
}

The test executable gets compiled with CMake:
add_executable(street_environment_test ${TESTS})
target_link_libraries(street_environment_test PRIVATE street_environment gtest gtest_main)

The code compiles but it fails during runtime with:

C++ exception with description "Trying to save an unregistered polymorphic type (street_environment::RoadLane).
Make sure your type is registered with CEREAL_REGISTER_TYPE and that the archive you are using was included (and registered with CEREAL_REGISTER_ARCHIVE) prior to calling CEREAL_REGISTER_TYPE.
If your type is already registered and you still see this error, you may need to use CEREAL_REGISTER_DYNAMIC_INIT." thrown in the test body.

As you see, I'm already using CEREAL_REGISTER_TYPE and CEREAL_REGISTER_DYNAMIC_INIT but it is still not working.

Thanks for your help.

w.shan...@gmail.com

unread,
Jun 22, 2015, 11:06:11 PM6/22/15
to cere...@googlegroups.com, hans.kirc...@gmail.com
Can you let me know if replacing the macro CEREAL_FORCE_DYNAMIC_INIT with the following solves the issue?

#define CEREAL_FORCE_DYNAMIC_INIT(LibName)                       \
  namespace cereal {                                             \
  namespace detail {                                             \
    void dynamic_init_dummy_##LibName();                         \
  } /* end detail */                                             \
  namespace {                                                    \
    void CEREAL_DLL_EXPORT dynamic_init_##LibName() CEREAL_USED; \
    void dynamic_init_##LibName()                                \
    {                                                            \
      ::cereal::detail::dynamic_init_dummy_##LibName();          \
    }                                                            \
  } } /* end namespaces */

Hans Kirchner

unread,
Jun 23, 2015, 5:57:42 AM6/23/15
to cere...@googlegroups.com, hans.kirc...@gmail.com
Thanks for the reply.
I replaced the code you gave me in polymorphic.hpp but there seems to be no difference: The same runtime error occurs.

I will try to implement a standalone example.

Any help appreciated.

Hans Kirchner

unread,
Jun 29, 2015, 5:49:33 AM6/29/15
to cere...@googlegroups.com, hans.kirc...@gmail.com
Alright, I figured out the problem:
The RoadLane class inherits from polyLine2f AND EnvironmentObject -> Cereal is not able to handle this case and fails to deserialize it properly.

I made an example and pushed it on github to make it clear:


- I have two base classes Base and OtherBase and a class that derives from both base classes called Derived.
- I made a test case with googletest that tries to serialize and deserialize a Derived instance that is wrapped in a std::shared_ptr of Base / OtherBase.

The test case for OtherBase fails but if you swap the inheritance from

class Derived : public Base, public OtherBase

to

class Derived : public OtherBase, public Base

the test case for Base fails.

Has anyone any idea why this happens? It seems like bug in cereal for me.


Am Dienstag, 23. Juni 2015 05:06:11 UTC+2 schrieb w.shan...@gmail.com:

w.shan...@gmail.com

unread,
Jun 29, 2015, 7:38:02 PM6/29/15
to cere...@googlegroups.com, hans.kirc...@gmail.com
Some kind of bug with cereal, probably related to: https://github.com/USCiLab/cereal/issues/188
Reply all
Reply to author
Forward
0 new messages