Exceptions

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Eric

    Exceptions

    I have been researching how exceptions and dynamic_cast work to
    determine if I will use either feature for a game-console application.
    I have a few pre-concieved notions and questions that I was hoping
    some people here could validate/answer.

    PRECONCEIVED NOTION #1: Common implementations of dynamic_cast<>
    (VC++, GCC) rely on the presence of type_info objects. The use of
    strcmp() instead of type_info pointer-equivalence in common
    implementations is used ONLY to support non-statically linked
    applications (.dll's & such). Other than this requirement,
    dynamic_cast<> conceptually would never need the type_info::name
    strings. typeid(), on the other hand, must have type_info::name
    strings to fulfill it's function regardless of whether the app is
    entirely statically linked or not.

    QUESTION #1: Given that I am writing a statically-linked game-console
    app and I am only interested in dynamic_cast and not typeid(), it
    would benefit me to not have type_info::name strings added to my app
    and have dynamic_cast implemented using type_info pointer equivalence.
    Can gcc do this??


    PRECONCEIVED NOTION #2: Exception handling (the more attractive
    feature to me) actually requires dynamic_cast<> to implement the
    catch-by-type mechanism, which in turn requires strcmp() to support
    non-statically linked apps, which in turn requires a full
    type_info::name string for every type in my code regardless of whether
    or not it is ever thrown.

    QUESTION #2: Given that this amounts to unnecessary size-bloat for my
    statically linked game-console app, does anyone know if gcc can
    implement catch-by-type using type_info pointer equivalence and
    suppress the type_info::name strings?


    PRECONCEIVED NOTION #3: The best implementations of exception handling
    out there use the zero-runtime-cost model (I understand that VC++ does
    not, but gcc does). I understand that this model has no performance
    penalties when not throwing because the stack is unwound using an
    exteral table of ip-sorted elements rather than inserting code into
    every function. In addition to the typename strings that are
    theoretically irrelevant to statically linked apps, zero-runtime-cost
    models also have to add this instruction-pointer table to the app, and
    the table must cover every single function in the code regardless of
    whether or not it throws.

    QUESTION #3: Can anyone characterize the structure of the elements in
    such a table so that I can get my head around the size implications of
    it? Is there one entry per instantiation of objects with actual
    destructors?


    Thanks for any insight you can give on any of these issues.

    -Eric
  • Ron Natalie

    #2
    Re: Exceptions


    "Eric" <ericjhart@yaho o.com> wrote in message news:fdc57b51.0 402190914.1ef6e a37@posting.goo gle.com...
    ..
    Most of your questions about internals of particular compilers or how they may
    be forced to deviate from standard behavior is not appropriate for this group.
    You'd be better off asking in microsoft.publi c.vc.* for VC++ or the gnu.gcc
    groups for gcc.
    [color=blue]
    > PRECONCEIVED NOTION #1: Common implementations of dynamic_cast<>
    > (VC++, GCC) rely on the presence of type_info objects[/color]

    I'll venture this is wrong in general. There's no requirement that type_info::name
    is UNIQUE (and it frequently isn't).
    [color=blue]
    > Other than this requirement,
    > dynamic_cast<> conceptually would never need the type_info::name
    > strings.[/color]

    Don't agree. Why would dynamic libraries need or care about type_info::name
    for this? All that is necessary is some resolved per-class value. Certainly linkers
    can handle the single definition of some object (like the vtable) accross libraries.
    [color=blue]
    > QUESTION #1: Given that I am writing a statically-linked game-console
    > app and I am only interested in dynamic_cast and not typeid(), it
    > would benefit me to not have type_info::name strings added to my app
    > and have dynamic_cast implemented using type_info pointer equivalence.
    > Can gcc do this?[/color]

    Many compilers (including visual C++ and I'm assuming GCC)...have options
    to ignore certain parts of the langauge.[color=blue]
    >
    > PRECONCEIVED NOTION #2: Exception handling (the more attractive
    > feature to me) actually requires dynamic_cast<> to implement the
    > catch-by-type mechanism, which in turn requires strcmp() to support
    > non-statically linked apps, which in turn requires a full
    > type_info::name string for every type in my code regardless of whether
    > or not it is ever thrown.[/color]

    Again, I don't know why you think strcmp has anything to do with this.
    Further, dynamic typing doesn't apply to exceptions. The static type
    of the object thrown must be mapped. While it might be possible or
    useful to share parts of this facility with the RTTI information, it's not
    required, and I can tell you Visual C++ doesn't do that.
    [color=blue]
    > QUESTION #2: Given that this amounts to unnecessary size-bloat for my
    > statically linked game-console app, does anyone know if gcc can
    > implement catch-by-type using type_info pointer equivalence and
    > suppress the type_info::name strings?[/color]

    Your question is nonsense in light of the invalid assumption of your notion.

    Comment

    • red floyd

      #3
      Re: Exceptions

      Eric wrote:
      [color=blue]
      >
      > PRECONCEIVED NOTION #2: Exception handling (the more attractive
      > feature to me) actually requires dynamic_cast<> to implement the
      > catch-by-type mechanism, which in turn requires strcmp() to support
      > non-statically linked apps, which in turn requires a full
      > type_info::name string for every type in my code regardless of whether
      > or not it is ever thrown.
      >
      > QUESTION #2: Given that this amounts to unnecessary size-bloat for my
      > statically linked game-console app, does anyone know if gcc can
      > implement catch-by-type using type_info pointer equivalence and
      > suppress the type_info::name strings?[/color]

      I believe notion is incorrect. AFAIK, exception handling uses the same
      rules as conversion and argument passing. That is, derived can be used
      as a base, but not vice versa. My understanding is that dynamic_cast<>
      is used for safe downcasting (base class to derived class).

      Any gurus out there are welcome to flame my obvious ignorance :-)

      Comment

      • Rolf Magnus

        #4
        Re: Exceptions

        Eric wrote:
        [color=blue]
        > QUESTION #1: Given that I am writing a statically-linked game-console
        > app and I am only interested in dynamic_cast and not typeid(), it
        > would benefit me to not have type_info::name strings added to my app
        > and have dynamic_cast implemented using type_info pointer equivalence.
        > Can gcc do this??[/color]

        I have no idea, and I don't know why you want that. But you might want
        to ask in a newsgroup like gnu.g++.help, which is better for g++
        specific quesitons like yours.
        [color=blue]
        > PRECONCEIVED NOTION #2: Exception handling (the more attractive
        > feature to me) actually requires dynamic_cast<> to implement the
        > catch-by-type mechanism, which in turn requires strcmp() to support
        > non-statically linked apps, which in turn requires a full
        > type_info::name string for every type in my code regardless of whether
        > or not it is ever thrown.[/color]

        Why do you think that exception handling has anything to do with
        dynamic_cast or type_info at all? Actually, you can switch RTTI off
        completely in g++ and still use exceptions.
        [color=blue]
        > QUESTION #3: Can anyone characterize the structure of the elements in
        > such a table so that I can get my head around the size implications of
        > it? Is there one entry per instantiation of objects with actual
        > destructors?[/color]

        I don't know the answer to that question, but again would advice you to
        ask in gnu.g++.help.

        Comment

        • lilburne

          #5
          Re: Exceptions

          Eric wrote:[color=blue]
          > I have been researching how exceptions and dynamic_cast work to
          > determine if I will use either feature for a game-console application.
          > I have a few pre-concieved notions and questions that I was hoping
          > some people here could validate/answer.
          >
          >
          > QUESTION #2: Given that this amounts to unnecessary size-bloat for my
          > statically linked game-console app, does anyone know if gcc can
          > implement catch-by-type using type_info pointer equivalence and
          > suppress the type_info::name strings?[/color]

          What evidence do you have that dynamic_cast results in code
          bloat?

          Personally I'd be a little suspicious of code that was
          written to specifically throw exceptions. dynamic_cast only
          throws if you are casting to a reference.
          [color=blue]
          >
          > PRECONCEIVED NOTION #3: The best implementations of exception handling
          > out there use the zero-runtime-cost model (I understand that VC++ does
          > not, but gcc does). I understand that this model has no performance
          > penalties when not throwing because the stack is unwound using an
          > exteral table of ip-sorted elements rather than inserting code into
          > every function.[/color]


          Perhaps not. The last time I check GCC 3.3.2 was 5 times
          slower with exceptions than asserts:


          Performance seems to vary from compiler release to compiler
          release.

          Comment

          • Rolf Magnus

            #6
            Re: Exceptions

            lilburne wrote:
            [color=blue][color=green]
            >> PRECONCEIVED NOTION #3: The best implementations of exception
            >> handling out there use the zero-runtime-cost model (I understand that
            >> VC++ does
            >> not, but gcc does). I understand that this model has no performance
            >> penalties when not throwing because the stack is unwound using an
            >> exteral table of ip-sorted elements rather than inserting code into
            >> every function.[/color]
            >
            >
            > Perhaps not. The last time I check GCC 3.3.2 was 5 times
            > slower with exceptions than asserts:
            > http://groups.google.com/groups?&as_...c%241pao1h%241[/color]
            40ID-203936.news.uni-berlin.de[color=blue]
            >
            > Performance seems to vary from compiler release to compiler
            > release.[/color]

            Either the gcc version for your platform has a bug related to exceptions
            or your installation is somehow broken. Look at the following:

            $ g++ --version
            g++ (GCC) 3.3.2
            Copyright (C) 2003 Free Software Foundation, Inc.
            This is free software; see the source for copying conditions. There is
            NO
            warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
            PURPOSE.
            $ cat point.C
            #include <iostream>
            #include <ctime>
            #include <cmath>
            #include <limits>
            #include <cassert>

            using namespace std;

            class Point{
            double m_x;
            double m_y;
            double m_z;
            public:
            Point() {
            m_z = numeric_limits< double>::max();
            }
            Point(double x, double y, double z) {set(x,y,z);}
            void set(double x, double y, double z) {m_x = x, m_y =
            y; m_z = z;}
            const double& x() const { return m_x;}
            const double& y() const { return m_y;}
            const double& z() const { return m_y;}
            bool coincident(cons t Point& a, double eps) const;
            bool is_valid() const {
            return m_z != numeric_limits< double>::max();
            }
            };


            #ifdef USE_EXCEPTIONS
            bool Point::coincide nt(const Point& a, double eps) const
            {
            if (!is_valid()) {
            throw int(1);
            }
            return abs(x()-a.x()) < eps &&
            abs(y()-a.y()) < eps &&
            abs(z()-a.z()) < eps;
            }

            void test(const Point& a, const Point& b)
            {
            try {
            a.coincident(b, 1e-5);
            }
            catch (int) {
            cout << "caught exception" << endl;
            }
            }
            #else
            bool Point::coincide nt(const Point& a, double eps) const
            {
            assert(is_valid ());
            return abs(x()-a.x()) < eps &&
            abs(y()-a.y()) < eps &&
            abs(z()-a.z()) < eps;
            }

            void test(const Point& a, const Point& b)
            {
            a.coincident(b, 1e-5);
            }
            #endif


            int main()
            {
            time_t start = time(0);
            Point a(10.0,10.0,20. 0);
            Point b(10.0,10.0,20. 0);
            for (int i = 0; i < 10000000; ++i) {
            test(a,b);
            }

            cout << time(0) - start << endl;
            return 0;
            }
            $ g++ point.C -O2 -DUSE_EXCEPTIONS
            $ time ./a.out
            0

            real 0m0.371s
            user 0m0.367s
            sys 0m0.001s
            $ g++ point.C -O2
            $ time ./a.out
            1

            real 0m0.370s
            user 0m0.366s
            sys 0m0.002s


            As you can see, your program isn't 5 times slower with exceptions than
            without on my gcc 3.3.2 installation. The difference is actually
            smaller than the measurement inaccuracy.


            Comment

            • lilburne

              #7
              Re: Exceptions

              Rolf Magnus wrote:[color=blue]
              > lilburne wrote:
              >
              >
              > Either the gcc version for your platform has a bug related to exceptions
              > or your installation is somehow broken. Look at the following:
              >
              > $ g++ --version
              > g++ (GCC) 3.3.2
              > Copyright (C) 2003 Free Software Foundation, Inc.
              > This is free software; see the source for copying conditions. There is
              > NO
              > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
              > PURPOSE.
              > $ g++ point.C -O2 -DUSE_EXCEPTIONS
              > $ time ./a.out
              > 0
              >
              > real 0m0.371s
              > user 0m0.367s
              > sys 0m0.001s
              > $ g++ point.C -O2
              > $ time ./a.out
              > 1
              >
              > real 0m0.370s
              > user 0m0.366s
              > sys 0m0.002s
              >
              >
              > As you can see, your program isn't 5 times slower with exceptions than
              > without on my gcc 3.3.2 installation. The difference is actually
              > smaller than the measurement inaccuracy.
              >[/color]

              I was mistaken about the version of GCC it is 3.3.1 not
              3.3.2. Perhaps 3.3.1 was broke.

              22:37:48 ~ > g++ --version
              g++ (GCC) 3.3.1 (cygming special)
              Copyright (C) 2003 Free Software Foundation, Inc.
              This is free software; see the source for copying
              conditions. There is NO
              warranty; not even for MERCHANTABILITY or FITNESS FOR A
              PARTICULAR PURPOSE.


              22:34:51 ~ > g++ point.C -O2 -DUSE_EXCEPTIONS
              22:35:42 ~ > time ./a.exe
              lapsed time: 32

              real 0m34.058s
              user 0m0.000s
              sys 0m0.000s
              22:36:32 ~ > g++ point.C -O2
              22:37:32 ~ > time ./a.exe
              lapsed time: 6

              real 0m7.168s
              user 0m0.000s
              sys 0m0.000s



              Comment

              • Risto Lankinen

                #8
                Re: Exceptions


                "Eric" <ericjhart@yaho o.com> wrote in message
                news:fdc57b51.0 402190914.1ef6e a37@posting.goo gle.com...[color=blue]
                >
                > PRECONCEIVED NOTION #2: Exception handling (the more attractive
                > feature to me) actually requires dynamic_cast<> to implement the
                > catch-by-type mechanism, which in turn requires strcmp() to support
                > non-statically linked apps, which in turn requires a full
                > type_info::name string for every type in my code regardless of whether
                > or not it is ever thrown.
                >
                > QUESTION #2: Given that this amounts to unnecessary size-bloat for my
                > statically linked game-console app, does anyone know if gcc can
                > implement catch-by-type using type_info pointer equivalence and
                > suppress the type_info::name strings?[/color]

                Exception handling can be implemented using static type checking, and
                therefore it doesn't necessarily require type_info structs. If the size of
                the type_info is a concern, check out other compilers for your platform
                for whether they implement exceptions without using the RTTI.

                - Risto -


                Comment

                • Rolf Magnus

                  #9
                  Re: Exceptions

                  lilburne wrote:
                  [color=blue][color=green]
                  >> $ g++ point.C -O2 -DUSE_EXCEPTIONS
                  >> $ time ./a.out
                  >> 0
                  >>
                  >> real 0m0.371s
                  >> user 0m0.367s
                  >> sys 0m0.001s
                  >> $ g++ point.C -O2
                  >> $ time ./a.out
                  >> 1
                  >>
                  >> real 0m0.370s
                  >> user 0m0.366s
                  >> sys 0m0.002s
                  >>
                  >>
                  >> As you can see, your program isn't 5 times slower with exceptions
                  >> than without on my gcc 3.3.2 installation. The difference is actually
                  >> smaller than the measurement inaccuracy.
                  >>[/color]
                  >
                  > I was mistaken about the version of GCC it is 3.3.1 not
                  > 3.3.2. Perhaps 3.3.1 was broke.
                  >
                  > 22:37:48 ~ > g++ --version
                  > g++ (GCC) 3.3.1 (cygming special)
                  > Copyright (C) 2003 Free Software Foundation, Inc.
                  > This is free software; see the source for copying
                  > conditions. There is NO
                  > warranty; not even for MERCHANTABILITY or FITNESS FOR A
                  > PARTICULAR PURPOSE.
                  >
                  >
                  > 22:34:51 ~ > g++ point.C -O2 -DUSE_EXCEPTIONS
                  > 22:35:42 ~ > time ./a.exe
                  > lapsed time: 32
                  >
                  > real 0m34.058s
                  > user 0m0.000s
                  > sys 0m0.000s
                  > 22:36:32 ~ > g++ point.C -O2
                  > 22:37:32 ~ > time ./a.exe
                  > lapsed time: 6
                  >
                  > real 0m7.168s
                  > user 0m0.000s
                  > sys 0m0.000s[/color]

                  I still wonder why it takes so extremely long on your machine. I mean,
                  even the "fast" non-exception version took over 7 seconds on your
                  machine and only 0.37 seconds on mine. Even when I use -O0 to turn off
                  all optimizations, the program doesn't take longer than about 1.5
                  seconds here (again, no significant difference between exception and
                  non-exception version).


                  Comment

                  • Eric

                    #10
                    Re: Exceptions

                    "Risto Lankinen" <rlankine@hotma il.com> wrote in message news:<w%iZb.990 3$g4.200127@new s2.nokia.com>.. .[color=blue]
                    > "Eric" <ericjhart@yaho o.com> wrote in message
                    > news:fdc57b51.0 402190914.1ef6e a37@posting.goo gle.com...[color=green]
                    > >
                    > > PRECONCEIVED NOTION #2: Exception handling (the more attractive
                    > > feature to me) actually requires dynamic_cast<> to implement the
                    > > catch-by-type mechanism, which in turn requires strcmp() to support
                    > > non-statically linked apps, which in turn requires a full
                    > > type_info::name string for every type in my code regardless of whether
                    > > or not it is ever thrown.
                    > >
                    > > QUESTION #2: Given that this amounts to unnecessary size-bloat for my
                    > > statically linked game-console app, does anyone know if gcc can
                    > > implement catch-by-type using type_info pointer equivalence and
                    > > suppress the type_info::name strings?[/color]
                    >
                    > Exception handling can be implemented using static type checking, and
                    > therefore it doesn't necessarily require type_info structs. If the size of
                    > the type_info is a concern, check out other compilers for your platform
                    > for whether they implement exceptions without using the RTTI.
                    >
                    > - Risto -[/color]

                    Forgive my ignorance about common compiler-implementation strategies
                    regarding exceptions - I've just started trying to get my head around
                    it. That said, I have to ask you how exception handling can possibly
                    be statically type checked by *any* implementation. To me, that says
                    that "throw Error" is bound to some other "catch(Erro r&)" statically
                    at compile time. That is, of course, impossible.

                    In any implementation, doesn't the thrown type have to be represented
                    by some value at runtime. In fact, "catch by type" is an illusion...
                    it's it really "catch by compiler-generated value that represents
                    type". That's really akin to rtti (even if you don't call it rtti).
                    I had assumed that type_info was a likely candidate for this "value",
                    but I concede that the standard says nothing about it *having* to be.
                    Still, it's a value nontheless. Further, it must be a value that
                    works accross dynamically linked boundaries - otherwise a dll couldn't
                    throw a type that was caught by the app that loaded it. That rules
                    out vtbl ptrs or any other "simple equivalence" checks - it would have
                    to be something more universal, like a name (hence my assumption that
                    type_info::name was a likely candidate).

                    Does anyone understand me or am I totally off the deep end?

                    Thanks,

                    -Eric

                    Comment

                    • Risto Lankinen

                      #11
                      Re: Exceptions

                      Hi!

                      "Eric" <ericjhart@yaho o.com> wrote in message
                      news:fdc57b51.0 402201210.1d973 32c@posting.goo gle.com...[color=blue]
                      > "Risto Lankinen" <rlankine@hotma il.com> wrote in message[/color]
                      news:<w%iZb.990 3$g4.200127@new s2.nokia.com>.. .[color=blue][color=green]
                      > >
                      > > Exception handling can be implemented using static type checking, and
                      > > therefore it doesn't necessarily require type_info structs. If the size[/color][/color]
                      of[color=blue][color=green]
                      > > the type_info is a concern, check out other compilers for your platform
                      > > for whether they implement exceptions without using the RTTI.
                      > >
                      > > - Risto -[/color]
                      >
                      > Forgive my ignorance about common compiler-implementation strategies
                      > regarding exceptions - I've just started trying to get my head around
                      > it. That said, I have to ask you how exception handling can possibly
                      > be statically type checked by *any* implementation. To me, that says
                      > that "throw Error" is bound to some other "catch(Erro r&)" statically
                      > at compile time. That is, of course, impossible.[/color]

                      In a nutshell, RTTI is one way (and clearly the most obvious
                      way based on the number of people who assume that RTTI is
                      strictly necessary for exception handling), but not the only one.

                      Another way is to generate an unwinder for every exception
                      type that can be caught. It will know of all available catchers
                      of the same type. The unwinder will check the stack, and if
                      it finds out that a function in the stack has a handler for that
                      exception type, it will call the handler, or otherwise it will call
                      the local parameter cleanup routine for that function, and go
                      on with the next function in the return stack.

                      (What I wrote about "functions" handling exceptions above
                      also applies to nameless statement blocks which, too, must
                      have their own cleanup at the point where the corresponding
                      scope closes [if they define local variables], and be identified
                      by the return address in the stack. This fact nicely illustrates
                      that catchers are really function objects on their own right and
                      not only in association of some function containing them in the
                      source code.)

                      Whenever you code a function that catches some new type,
                      a new unwinder is created. Whenever you code a function
                      that catches some type that is also being caught somewhere
                      else, the unwinder is augmented to include your new handler
                      in its list of handlers of that type. Augmentation thru multiple
                      compilation units catching the same exception can be dealt
                      with some segmentation magic (basically the pointers to all
                      unwinders will go to some common data segment, and when
                      the initial unwinder is called, it will know how to chain with
                      the corresponding handlers in other compilation units).

                      The thrower knows the exact type of the exception, hence
                      the compiler could simply generate a JMP instruction to the
                      unwinder of that particular exception type, which is easy to
                      do at compile-time. Certain weak-reference mechanisms
                      need to be implemented by the linker (or a "stub" unwinder
                      must be created at the point of throw) to cater for situations
                      where a thrown type may have no catcher at all.

                      In real world, there may be only one unwinder that is driven
                      by a 2D matrix, indexed by thrown types and caught types.
                      Instead of generating/calling unwinders, the catchers merely
                      just add a row in the matrix indicating the types they catch,
                      and the throwers pass matrix column index as an argument
                      to the unwinder.

                      Which brings us to the point, that RTTI type_info is one way
                      to use as a column index in such a matrix, or even implement
                      the whole matrix (by applying sparce matrix implementation
                      techniques using type_info as the node type) in a reasonably
                      space efficient - but not run-time efficient - manner. That is
                      actually one explanation why throwing exceptions in general
                      have a high run-time cost.

                      - Risto -


                      Comment

                      Working...