[Serialization] 1.56.0 - unregistered_class exception while using EXPORTs
I've been pulling my hair out for a couple of days trying to get this to
work.
When I serialize something from a base pointer, it throws an
"unregistered_class" exception.
I know the type of object that's being serialized and that class has
"BOOST_CLASS_EXPORT_KEY" in the header and "BOOST_CLASS_EXPORT_IMPLEMENT"
in the cpp file with the same name.
In the save and load functions I also have:
boost::serialization::void_cast_register(
static_cast
Todd Seiler wrote
I've been pulling my hair out for a couple of days trying to get this to work.
When I serialize something from a base pointer, it throws an "unregistered_class" exception.
On save or on load? I presume its on load.
I know the type of object that's being serialized and that class has "BOOST_CLASS_EXPORT_KEY" in the header and "BOOST_CLASS_EXPORT_IMPLEMENT" in the cpp file with the same name.
For all of the derived classes - right?
Each derived class should serialize it's base with
.... base_object
should not be necessary if you're serialization all the base objects < /quote The base class is an abstract base class with one pure virtual function method. But here are the differences: <quote > 1) I tried using the "ASSUME_ABSTRACT....." macro. That didn't do anything for me.
shouldn't make any difference these days
2) The abstract base class also has a cpp file with some code in it. I'm not sure if that matters or not...
Shouldn't be a problem. Just make sure all the save/load functions serialize their base objects.
Here's the thing. I can get the derived class's "save" method to be called with this code:
std::ofstream o(case_path_ + "/" + file_name); if (o.good()) {
// MUST HAVE THIS boost::serialization::void_cast_register<Derived, Base>( static_cast<Derived*>(NULL), static_cast<Base*>(NULL));
boost::archive::polymorphic_text_oarchive oa(o); boost::archive::polymorphic_oarchive & oa_interface = oa; oa_interface << base_ptr; } Having the void_cast_register() there sort of defeats the purpose though. I shouldn't need to pre-register them. In all the examples, I see the void_cast_register() inside of the "save" and "load" methods, which is what I have already.
which examples?
All my serialization code resides in cpp files.
Also, the serialization code resides in a static lib. But the archive creation and the action to serialize is performed in a dynamic lib.
REDFLAG - in some environments this is a big no-no as static and dynamic libraries have different c library implementations. There is no guarantee that mixing static and dynamic libraries will work. I recommend using either all one or all the other. Since you're interested in polymorphic archives - you'll likely want to use all dynamic.
I am also using polymorphic archives everywhere.
where? in another application? on another planet?
I've also forced template instantiation of all serialization code and polymorphic archive interface stuff.
But most linkers strip out code which is known to be called. This is particularly problematic for dlls. The serialization library does bunch of stuff to make sure such code is not dropped.
Any clue?
Look at more of the tests and example relating to export. Robert Ramey -- View this message in context: http://boost.2283326.n4.nabble.com/Serialization-1-56-0-unregistered-class-e... Sent from the Boost - Users mailing list archive at Nabble.com.
It's on load.
I'm just testing with a single derived class.
My base class is an abstract polymorphic base class. So I didn't use
"base_object
On 8/19/14 8:40 PM, aragonsr wrote:
It's on load.
I'm just testing with a single derived class.
My base class is an abstract polymorphic base class. So I didn't use "base_object
(this)" in the derived class. Is this correct? There's nothing in the base class to serialize. it sounds like you're telling me, even if it's abstract, I should go ahead and use "base_object (this)"? I'll give that a shot.. I guess.. I meant examples in the documentation. Specifically: http://www.boost.org/doc/libs/1_56_0/libs/serialization/doc/serialization.ht... http://www.boost.org/doc/libs/1_56_0/libs/serialization/doc/serialization.ht...
I'm using polymorphic archives throughout the application in all the object's I'm trying to serialize / deserialize. And I'm explicitly instantiating the templates like the documentation says.
"But most linkers strip out code which is known to be called." That doesn't make sense. Do you mean "which is NOT called"?
I didn't know about the dll static lib thing. Never thought about it. This gives me something to chew on for a while. Thanks!
-- View this message in context: http://boost.2283326.n4.nabble.com/Serialization-1-56-0-unregistered-class-e... Sent from the Boost - Users mailing list archive at Nabble.com.
As it turns out, it appears that you were correct when you stated that mixing static and dynamic libs is a bad idea. I had no idea. After running several different tests, I was able to get it to work. I put the serialization code inside the same dll that the serialization operation was initiated from and that worked. I then put the serialization code inside of a different dll and initiated the serialization from a separate dll. This also worked. I also tested using the manual void_register call and implementing a dummy serialize method in the base class, both worked when I took the static lib out of the equation. Thanks a ton!
aragonsr wrote
It's on load.
I'm just testing with a single derived class.
My base class is an abstract polymorphic base class. So I didn't use "base_object
(this)" in the derived class. Is this correct? There's nothing in the base class to serialize. it sounds like you're telling me, even if it's abstract, I should go ahead and use "base_object (this)"? I'll give that a shot.. I guess..
Basically, the void_cast ... has to be there. base_object includes it. If you don't user base_object, you have to use void_cast. That is you can either include null serialization in the base or use void_cast... Either should work just as well.
"But most linkers strip out code which is known to be called." That doesn't make sense. Do you mean "which is NOT called"?
struct A {..}; // abstract base class struct B : public A {...}; iarchive >> a; // makes no reference to type B. Sooo the compiler will say - hmmm - no one is referencing B::save and B::load so we might as well just eliminate this "dead" code. That's what it does. Problem isn't discovered until the program is run and the downcast can't be found. It's even worse. Some compilers only do the "dead code stripping" when running in release mode. So your program works with debugging but fails on release. No fun unless you can ask on this list. But wait! it's even worse! When building DLL dead code stripping may well not occur since the compiler knows that there will be a lot of unreferenced functions and can't know that it should strip dead code. So things might work when using as a DLL but not when using a static library. The compiler say - oh, no need to include functions where no one calls them (that I can see).
I didn't know about the dll static lib thing. Never thought about it. This gives me something to chew on for a while. Thanks!
Of course this complicates things as well. The source of this problem is that all the issues associated with static and runtime linking are totally undefined by the C++ standard and are in fact considered as issues totally outside the language itself. But we also want optimized code. These propositions conflict. Perhaps someday this might be addressed by including the concept of "modules" in the language. But it's not clear if that will ever happen or if it does happen if it will be useful to actual programers such as ourselves. The concept of C++ plugins implemented with runtime linking is very, very useful on a large project which needs to be updated after deployment. However, one can't "just do it". One has to spend real effort doing this. I have a few suggestions: a) use dynamic linking for both mainline and all dlls. This helps with the "dead code stripping" problem and the one definition problem. In these case a C library function will only appear in the C library DLL and no where else so you won't accidentally have multiple "equivalent" versions of the same function in your final program. First they're not always equivalent. Second it saves space to not duplicate. Third, a view functions such as stringtok keep an internal state variable - they are not idempotent. When multiple versions are included, there will be multiple instances of these internal variables with can create a problem which is incredibly difficult to find. b) Don't use inlined functions in derived classes. Put all code in the separate *.cpp files. This avoids violations of one definition rule. c) Be prepared to really think about where the code is that one is going to call. You just have to spend time planning this out. Robert Ramey -- View this message in context: http://boost.2283326.n4.nabble.com/Serialization-1-56-0-unregistered-class-e... Sent from the Boost - Users mailing list archive at Nabble.com.
participants (3)
-
aragonsr
-
Robert Ramey
-
Todd Seiler