The problem is when one uses BOOST_CLASS_EXPORT
This creates a static object which is constructed at pre-execution time - before calling main. This static object adds itself to a global table which points to the functions to serialize/deserialize pointers to derived objects not mentioned by name. Thus the code to serialize/deserialise these objects is instantiated even though there may be no place in the program which does ar << "derived object"
So far - so good.
When a BOOST_CLASS_EXPORT is used in a DLL the static object is created which the DLL is loaded and destroyed when the DLL is unloaded. Upon construction/destruction, the pointer to the instanticiated code is added/deleted from this global table.
So far - so good.
In this case the DLL loads a derived class - which through the base_object syntax includes serialization/deserialization of the base class. In this case, the base class serialization is also in the main executable. So when the second instance (the DLL version) is loaded another instance of the base class code is added to the global table. This triggers and exception as we can't have to possible different instantiations of the same code. This create the possibility that the when the DLL is unloaded the table entry corresponding the the instantiation in the main program might be removed - thus leaving an reference to he code in the now removed DLL.
Short term solution.
Hmm - not sure. If ALL the base classes are in the DLL I don't think there should be a problem.
Long term solution.
The global table might include a handle to the code module which created the entry. This could be used to be sure that the correct entry is deleted as teh DLL is deleted. In windows there is a call to retrieve a handle to the current module - main, DLL etc. I don't know what the corresponding call is on a unix/cygwin/ etc environment. Any one is free to chime in here.
Robert Ramey
"Terence Wilson" wrote in message news:003701c69091$b43f68f0$2301a8c0@gjoob.com...
Dear Robert,
I have also been stymied by this bug, for me it is a show stopper because our application is composed of many DLL's rather than a single executable. If it would help you, I can provide a small VC8 project which demonstrates the issue. I'm motivated to help you fix the problem as your library could potentially be very useful in our work.
Could you please explain what you mean by registered twice? As I understand it, the base and derived classes should be registered, is this what you refer to or do you mean registered twice, the same class once in each module?
Thanks for your help,
Terence
------------------------------------------------------------------------------
From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Robert Ramey
Sent: Tuesday, June 13, 2006 1:23 PM
To: boost-users@lists.boost.org
Subject: Re: [Boost-users] boost::serialization unregistered_classexceptionswith DLL.
This has been bugging me for a while but I never really found the time to really track it down. Perhaps you could do a little sleuthing while your there. I would expect that the problem due to the fact that foobar_base is "registered" twice - once when the app starts up and a second time when the derived class DLL is "registered" when the DLL is loaded. So I believe that the problem would not appear if foobar_base were in the DLL as well.
The reason that I've enforce the restriction that serialization code be instanticiated only once was that when It was permitted multiple times, the "unregister" code would sometimes remove the wrong instance. So that things would crash in an unpredictable and obscure way. Its still not clear to me the best way to handle this. I guess that the eti has to be "registered" along with a handle to its code module (executable, dll or shared library). So far I haven't spent any time on investigating this.
Thanks for a good example which illustrates the problem in a digestable manner.
Robert Ramey
"Arjuna Balasingham" wrote in message news:004a01c68f13$3bae3120$56d8ac41@gatan.com...
Re: unregistered_class exceptions are thrown when the derived class are in an explicitly loaded DLL.
Hello,
In a nutshell, the problem that I have is that an "unregistered_class" exception is thrown when the derived class is defined/declared in a DLL that is explicitly loaded.
The problem as far as I can tell is that the derived class in dll and the derived class in the framework are being "registered" in two different instances (m_self->m_map.insert(eti); in "extended_type_info.cpp").
Exception is thrown when trying to serialize the foobar_derived_dll. It looks for "foobar_derived_dll" in the wrong instance of the m_map defined in the extened_type_info.cpp and then throws an exception.
Can anybody please help
The Application Structure is more or less as follows.
Common Framework Library Contains.
class foobar_base : public foobar_base
{
protected:
bool m_attr0;
public:
foobar_base() {}
template<class Archive>
void serialize(Archive & ar, const unsigned int /* file_version */){
std::cout << "serialize foobar_base\n";
ar & BOOST_SERIALIZATION_NVP(m_attr0);
}
}
class foobar_derived : public foobar_base
{
protected:
bool m_attr1;
public:
foobar_derived() {}
template<class Archive>
void serialize(Archive & ar, const unsigned int /* file_version */){
std::cout << "serialize foobar_derived_dll\n";
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(foobar_base);
ar & BOOST_SERIALIZATION_NVP(m_attr1);
}
}
BOOST_CLASS_EXPORT_GUID(foobar_derived, "foobar_derived")
Dynamic Link Library Contains (Includes Common Framework Library)
class foobar_derived_dll
{
protected:
bool m_attr2;
public:
foobar_derived_dll() {}
template<class Archive>
void serialize(Archive & ar, const unsigned int /* file_version */){
std::cout << "serialize foobar_derived_dll\n";
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(foobar_base);
ar & BOOST_SERIALIZATION_NVP(m_attr2);
}
}
BOOST_CLASS_EXPORT_GUID(foobar_derived_dll, "foobar_derived_dll")
Main Application (includes Common framework library & explictly lods Dynamic Link Library)
class foo {
public:
std::list > m_foovec;
public:
foo ( ) { };
~foo ( ) { };
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(m_foovec);
}
};
(..Include Framwork..)
int main() {
// load the DLL..
LoadLibrary(... DLL)"
foo f;
f.m_foovec.push_back( boost::shared_ptr(new foobar_derived(....
f.m_foovec.push_back( boost::shared_ptr(new foobar_derived_dll(....
std::string filename("c:\\tmp.txt");
try {
// write to file
std::ofstream ofs(filename.c_str());
assert(ofs.good());
boost::archive::text_oarchive oa(ofs);
oa << BOOST_SERIALIZATION_NVP(f);
ofs.close();
} catch (std::exception &e) {
std::cout << e.what() << std::endl;
}
}
----------------------------------------------------------------------------
_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
------------------------------------------------------------------------------
_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users