0

I tried to split some polymorphic classes to be serialized into a dll file. Then I get an exception for unregistered polymorphic type. The problem seems to be that the code create two instances of the map used to lookup polymorphic objects (Kept by template class cereal::detail::StaticObject). If I put the CEREAL_REGISTER_TYPE into the project that do the serialization, then everything works nice.
So I wonder if anyone know if it is possible to do some tricks to be able to do the registration in the dll file?
Is it possible to force the program to use the same instance of the cereal::detail::StaticObject class?

R.Undheim
  • 3
  • 2
  • See discussion on GitHub: https://github.com/USCiLab/cereal/issues/107 – Azoth Jul 14 '14 at 17:45
  • This is another problem. The problem here are that I get two instances of the cereal::detail::StaticObject class for each template type. One for each dll file. None of the maps are complete, but information split into the different dll files. I think that to fix this it must be possible to set the dllexport/dllimport storage-class attributes on the cereal::detail::StaticObject to make sure access is done only through one dll file. And it must also be possible to instantiate the cereal::detail::StaticObject in a cpp file. – R.Undheim Jul 16 '14 at 06:49
  • If you think this is another bug can you open up an issue? Easiest way for us to work on it. – Azoth Jul 16 '14 at 19:58
  • New issue added [#113](https://github.com/USCiLab/cereal/issues/113) – R.Undheim Aug 06 '14 at 07:53

2 Answers2

0

As of cereal v1.1.0 this problem can be solved by moving the polymorphic type registration to a header file, which will ensure that any translation unit including that header properly initializes its StaticObject. Just remember to include the archives you wish to bind to prior to calling the registration macro.

There's more information available on the [main cereal documentation] site(http://uscilab.github.io/cereal/polymorphism.html), which has also been updated for 1.1.

Azoth
  • 1,652
  • 16
  • 24
0

I managed to solve this problem with 1.3.0 (should work with 1.1 too) by having the following statements in an hpp in a DLL at the bottom of my DLL dependency chain. Let's call it core.dll. In that DLL I will have a file called config.hpp with the following traditional macro. CMake will define core_EXPORTS when generating the build scripts for core.dll

#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
#  if defined(core_EXPORTS)
#    define CORE_DECL __declspec(dllexport)
#  else
#    define CORE_DECL __declspec(dllimport)
#  endif
#endif

Then in another export.hpp in core.dll I have the following

namespace cereal {
    namespace detail {
        // these declspecs will ensure that the polymorphic loader/saver registrations will
        // all happen against the binding maps in core.dll
        template class CORE_DECL StaticObject<InputBindingMap<PortableBinaryInputArchive>>;
        template class CORE_DECL StaticObject<InputBindingMap<JSONInputArchive>>;
        template class CORE_DECL StaticObject<OutputBindingMap<PortableBinaryOutputArchive>>;
        template class CORE_DECL StaticObject<OutputBindingMap<JSONOutputArchive>>;
        // add similar statements for other archive types as needed
        template class CORE_DECL StaticObject<Versions>;
    } // namespace detail
} // namespace cereal

All other cpp files in the other dll projects will #include core/export.hpp thereby telling the linker to use the cereal StaticObjects in core.dll. If you debug the InputBindingCreator contructor you will notice that every class is now being registered in the same binding map.

I think it would be useful to add the above to the cereal documentation on this topic.