[cxx-abi-dev] trivial __dynamic_cast fails?

David Abrahams dave at boost-consulting.com
Sat Feb 28 14:41:42 UTC 2004


David Baraff <deb at pixar.com> writes:

> At Pixar, we've been making use of a type-system that piggy-backs off
> of RTTI.
> The only thing we require users to do is the following for each type
> they want to participate in the type system:
>
> ----source-file: derived.cpp-----
> #include "instantiateType.h"
> #include "derived.h"
>
> TF_TYPE_INSTANTIATE(Derived, TF_1_PARENT(Base));
> ----------------------------------
>
> At startup-time, the above macro injects into a registry that Derived
> has a parent, Base.
> (Presumably base has done the same, possibly saying it has no parents
> and really is a base.)
> If you have multiple parents, you can do e.g.
>
> TF_TYPE_INSTANTIATE(MyMultiClass, TF_3_PARENT(Base1, Base2, Base3));
> Along with inserting the parent/child info, the macro above also
> synthesizes cast functions to/from parent and child and adds them to
> the registry

Sounds familiar.
See http:://www.boost.org/boost/libs/python/src/object/inheritance.cpp

>  -- this is trivially done in the macro,  since static
> type information is available.  After this, at runtime, we simply use
> the typeid() operator on an object and use the RTTI type_info
> structure to do lookups in our type-registry, allowing for all the
> queries and conversions you'd imagine in functions that have no access
> to static type information.
>
> The only ugliness, in fact, is requiring users to add that macro in
> their source code.  It would be nice to avoid that.


You can do all this without the ugly macros, if you care ;-)
Boost.Python does it with templates.

  class_<X, bases<Y, Z, W> >("X")
      ...

But the user still has to say something.

> ------------------------------------------------------
> The __cxxabiv1 spec could let us avoid the macro ugliness.  (I say
> could because I'm quite leery about depending on constructs outside
> the language.  While Pixar is limited to linux and OsX right now,
> [i.e. both g++ compilers], you never know how things could change.)
>
> Anyway, we make use of the type facility to let our variant class
> [called TfAny, in fact!] hold onto a pointer of any type, and then let
> a user ask if it is holding that particular pointer type, or if it
> could be cast to that pointer type.  I don't see anyway that a query
> involving parent/child relationship can be done completely at
> run-time, by a class like boost::any without either the scheme I
> describe I above, or reliance on a facility like __cxxabiv1.  

See the code I posted.

> Since you create a virtual function which knows only one type, you
> can't ask it if a cast can succeed to an arbitrary static type, you
> *have* to be able to ask if it a cast to a type represented by a
> type_info can succeed.  And *that* can't be done within the language
> as it stands.

I'm not sure.

> You wrote
>>> Here's a biggy.  Consider the boost::any class.  Currently, if it
>>> holds a Derived* and you ask it for a Base*, I think it says "no can
>>> do."  Imagine if it could actually say "yes, I can give you back a
>>> Base*", because it could dynamically look up the parent chain, and do
>>> the address shift.
>>>
>>> That would make boost::any a heck of a lot more useful than it is
>>> today.
>>
>> boost::any could already be modified to do this, since it "knows" the
>> "Derived" type.  I've enclosed an implementation.  Seems to reveal EH
>> bugs in quite a few compilers, tho ;-)
>
> I don't understand what you mean by the above.  As I see it in the
> implementation, the any_cast<> operation must hit *exactly* the type
> actually being held or it fails.

You obviously didn't read the modified implementation I enclosed.

> The holder object can't answer the question "can your object be cast
> to some other type" without making use of the abi-specific
> functionality we are discussing.  Do you think it can?

Yes; the holder knows the static type; it can throw a pointer of that
type.  The cast operation can catch the pointer type it's looking
for, or fail the cast with catch(...).

> Anyway, to answer your other question about shifting addresses, it's
> trivial:
> (and Mark Mitchell patiently informed me that what I wanted was indeed
> sitting in the structure, if I'd just take the time to read
> carefully).
>
> In the code below, ArchGetDemangled() takes a const type_info& and
> returns the demangled string name:
>
> #include <cxxabi.h>
>
> void
> PrintParents(const std::type_info* ti)
> {
>      if (const abi::__si_class_type_info* siTi =
>          dynamic_cast<const abi::__si_class_type_info*>(ti)) {
>
> 		 // there is no offset between parent and base class
>          printf("%s", ArchGetDemangled(*siTi->__base_type).c_str());
>      }
>      else if (const abi::__vmi_class_type_info* vmiTi =
>          dynamic_cast<const abi::__vmi_class_type_info*>(ti)) {
>
>          for (size_t i = 0; i < vmiTi->__base_count; i++) {
>              printf("%s [offset %d]\n",
>                     ArchGetDemangled(*vmiTi->__base_info[i].__base_type).c_str(),
>                     (vmiTi->__base_info[i].__offset_flags) >>
>                     abi::__base_class_type_info::__offset_shift);
>          }
>      }
> }
>
> template <typename T>
> void PrintParents()
> {
>      printf("Parents of %s: ", ArchGetDemangled(typeid(T)).c_str());
>      PrintParents(&typeid(T));
>      printf("\n");
> }


Thanks; it'll take me some time to absorb that.

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




More information about the cxx-abi-dev mailing list