Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2006-12-18 16:41:37


"Robert Ramey" <ramey_at_[hidden]> writes:

> David Abrahams wrote:
>> "Robert Ramey" <ramey_at_[hidden]> writes:
>>
>>> David Abrahams wrote:
>>>> "Emil Dotchevski" <emildotchevski_at_[hidden]> writes:
>>>>
>>>>> Or did I completely misunderstand the documentation? Robert, was
>>>>> the intended meaning that *if* you explicitly call a function from
>>>>> foo.cpp, then using the class export macro guarantees that class
>>>>> foo is properly registered with the serialization library?
>>>
>>> My intention is and was that proper registration will occur whether
>>> or not the type is explicitly referred to.
>>
>> "Whether the type is explicitly referred to" is completely irrelevant.
>> The question is whether any objects or functions from the translation
>> unit containing the EXPORT are used.
>>
>> Did you intend that proper registration occur even if no objects or
>> functions from the translation unit containing the EXPORT are used?

You didn't answer my question. Will you answer the question?

> I don't see how one can determine at compile time whether or not an
> object of a particular type is going to be used. In fact, it may
> well vary from one exectution run to the next. The situation I had
> in mind is that of serialization of derived through an abstract base
> class.

"Of a particular type" is irrelevant. The question is whether any
objects or functions in the TU are going to be used. The compiler
only has to prove that none will be used, and it can optimize out the
TU. No, obviously that doesn't happen at compile-time; it happens at
link time.

> suppose one is going to load an archive. The sequence of events is
> very roughly:
>
> a) read the export tag
> b) look it up in the extended type info table
> c) using this pointer, lookup the deserializer function
> d) and invoke them
>
> So the extended type info table has to be initialized with all the
> types that might be in the archive. This is what export attempts
> to do. But when compiled for release mode, some compilers
> drop the deseralization code. The results in a run time error
> "unregistered type". I always interpreted this as the
> compilers droping code that was never explicitly called. This
> is what occurs when we have an executable or dll which
> contains entry points never called. Some compilers provide
> the keyword "__export" to tell the compilers that such functions
> shouldn't be dropped even though they don't seem to be called.
> So I used these to be sure the the specified code didn't get
> dropped. Perhaps I should have described this but

but?

>>> That was my goal and I believe it has been achieved for all
>>> compilers that boost supports.
>
>> I would be very surprised if that were the case for Metrowerks; as
>> pointed out by Emil, that compiler is very good at optimizing out
>> unused translation units.
>
> Well, that would explain one reason we've had so much problem
> with this comipiler - its too conforming!!!

Maybe, but there's also one bug (at least).

>>> Now it seems the question being raised is whether this is/was the
>>> right thing to do.
>>
>> No, I don't think that is the question at all, at least, not mine. My
>> question is what promises you can legitimately make to users about
>> what will happen, and whether you have made your promises sufficiently
>> explicit.
>
>
>> That's a legitimate thing to do, but I think you need to be very
>> explicit about what you're doing.
>
> Well, that's easy to fix. I guess that all we need to say is:
>
> a) functionality of export cannot be guarenteed to be made to work
> on all compilers.

I don't think that's sufficiently precise. EXPORT works just fine as
long as you ensure that some function in the TU gets called. You
could have 50 EXPORTs and one dummy function in the TU, called from
main(), that prevents it from getting linked out.

> b) If you want your code to be guarenteed to be portable to other
> compilers, don't use export - use explicit registration instead.

Too big a hammer, IMO.

>>Do any of your tests actually exercise the
>> case where the EXPORT is in a TU with no used functions or objects?
>
> Well, I thought demo_pimpl did this - but I looked at it and it doesn't
> use export.
>
> So I checked test_exported. Its only one translation unit so it doesn't
> explicitly test this situation - the derived class constructor is called
> explicitly. this could easily be moved to another *.cpp file to test
> this.
>
> I did find one thing that was new to me and very interesting:
>
> BOOST_CLASS_EXPORT(polymorphic_derived1)
>
> // MWerks users can do this to make their code work
>
> BOOST_SERIALIZATION_MWERKS_BASE_AND_DERIVED(polymorphic_base,
> polymorphic_derived1)
>
> which I had never seen before. I don't know if this is related in some way.

Sure you have; I pointed it out to you very explicitly when I checked
in the new export code. It's not related to the optimization; it is a
workaround for the Metrowerks bug we've been discussing elsewhere in
this thread.

>>
>>> - its just not guarenteed to be portable to new compilers.
>>
>> Or new versions of existing compilers.
>
> Obviously

Of course, if the compiler's docs say it will respect __export, then
you're pretty darned safe in the future.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk