Re: templates + RTTI + shared library = impossible?
On Jan 29, 12:27 am, "BGB / cr88192" <cr88...@hotmail.com> wrote:
"Dan Caugherty" <dan.caughe...@gmail.com> wrote in message
news:70f50143-2db9-482f-b255-8e1e5adaa6c9@q2g2000pre.googlegroups.com...
Explicit instantiation tells the compiler to generate the
code for that particular instantiation. Since it's a
function, the name (mangled, of course) gets added to the
list of external symbols and the function becomes callable
from outside, so the linker can resolve it.
This much I understand. My original question was that the type_info
instances for the value<> types were, for whatever reason, invisible
to the executable. This seems to be keeping dynamic_cast<> from
working from outside the library.
The only real solution seems to be instantiating static functions
explicitly within the shared lib to do the work of dynamic_cast<>.
This is annoying, but not terribly inconvenient. (And I haven't tried
it yet, so for all I know, it may not work.)
I guess I'm also wondering if this can be avoided somehow.
take note that RTTI often works by having a class contain a
vtable-pointer to a class-info structure, which usually points
to the superclass info, ...
dynamic_cast then, would involve walking the graph, checking
superclasses, and seeing if the target class is in the list
(usually by pointer-comparrison). if not found, then the
dynamic_cast fails.
now, what happens when one links with shared libraries?
What happens when one links with shared libraries depends very
much on the compiler and the system.
... consider this:
what if the linker only sees stuff (during linking) which is
in its own set of stuff being linked. so, different
class-info structures for the same class will merge, ...
now, with the same class in different libraries:
it does the same things, each library then ending up with their own versi=
ons
of whatever class-info structs are used.
so, the same class in different libs will have different info structures,
and hence not compare equal via a simple pointer-based check, hence, not
working.
Yes and no. First, of course, the information concerning any
one class is a sort of a package -- it's either all there, or
none of it is. Second, of course, access to this information is
through the vptr, so the compiler only needs to know about it in
constructors and destructors (when it sets or resets the vptr).
And of course, the most derived class must know about all of the
sub-classes (even if they are in a different DLL).
All of this means that if all of the constructors and
destructors of each class are in the same DLL (no inlining!),
then there's absolutely no reason for more than one instance of
the RTTI information.
In practice, the situation is a bit more varied (and people do
inline constructors or destructors). In the case of VC++, for
example, I've noticed that every DLL does get its copy of the
RTTI information -- which one you get depends not on where the
code for the constructor was generated, but where the
constructor was called. (Even in the case of non-inlined
constructors. I can't figure out why---it seems like they're
going to a lot of extra work just to make things more difficult
to use.) In the case of Unix, with the compilers I've seen, two
different solutions are used: either the compiler generates the
RTTI information in the object file which contains the first
non-inlined virtual function (exporting the symbol, of course),
or it generates the information in every module where it
generates code for a constructor or the destructor, merging them
during the link phase. (The first solution is probably a
hang-over from earlier days, when linkers didn't know how to
merge.) And if two DLL's contain the same (exported) symbol,
only the first one loaded is actually used, so if the RTTI
information is exported, all instances will share the same
address. About the only time I think you might get different
addresses is if the shared object is loaded with the RTLD_LOCAL
flag (thus, explicitely), and your class has inline constructors
or destructors.
(As a general rule, inline functions and templates don't work
well with dynamic linked libraries, and should be avoided when
dynamic linking is being used. And don't forget that the
compiler generated defaults are inline---if you're using dynamic
linking, be sure to declare and define things like the copy
constructor, even if the definition corresponds to what the
compiler would generate.)
similar issues can also manifest in other ways as well:
malloc/free not working between DLL's (I have ran into this
before with MSVC, where using malloc in one DLL and free in
another may actually cause the app to subsequently crash);
(this may or may not also apply to new/delete, but I have not
tested);
This is a purely Windows problem, present probably because
Windows doesn't bundle the CRT DLL's with the OS (I think). If
you link everything (the main and all of the DLL's) with the CRT
DLL's (option /MD or /MDd to cl, IIRC), then there's no problem.
(On the other hand, if you do this, you may have to deliver the
CRT DLL when you deploy your program.) The problem doesn't occur
under Unix first because this is the standard way of
proceding---since the CRT and the system API are in the same
shared object (libc.so), they're automatically bundled with the
OS. And secondly because the CRT will be implicitely loaded,
with RTLD_GLOBAL, so all of its symbols will be exported, and
all of the shared libraries will use the first instance loaded.
so, alas, DLL or shared-library / shared-object issues may
need to be treated with care, as it is not exactly the same as
is the case with static linking.
In general, I find that people use DLL's far too much. It's
rarely justified to use a DLL within an application: DLL's are
for interfacing with external software which is separately
installed (the system, a data base, etc.) or for plug-ins.
--
James Kanze