try/finally implementation in c++

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

    #1

    try/finally implementation in c++

    Hi all

    Its one of my little pragramming challenges to implement a try/finally
    construct in C++. I have done several implementations but they all have
    limitations. Have tried mostly using a destructor to execute the
    "finally" code. However this has the big limitation that the destructor
    cannot see local variables. Another approach that solves this problem
    is the following:

    {
    MyBaseException * handledExceptio n = NULL;
    try
    {
    <try code>
    }
    catch(MyBaseExc eption& e)
    {
    handledExceptio n = e.Clone();
    }

    <finally code>

    if (handledExcepti on)
    throw *handledExcepti on;
    }

    However, this method has the limitation that it works only for specific
    classes of exception objects.

    I'm curious to see other ideas

    Regards
    Alex

  • Noah Roberts

    #2
    Re: try/finally implementation in c++


    avasilev wrote:[color=blue]
    > Hi all
    >
    > Its one of my little pragramming challenges to implement a try/finally
    > construct in C++. I have done several implementations but they all have
    > limitations. Have tried mostly using a destructor to execute the
    > "finally" code. However this has the big limitation that the destructor
    > cannot see local variables.[/color]

    Not that I am recommending it but...

    It could if the destructor was part of a local struct containing those
    variables.

    Something to think about.

    Comment

    • Phlip

      #3
      Re: try/finally implementation in c++

      avasilev wrote:
      [color=blue]
      > I'm curious to see other ideas[/color]

      news:comp.lang. c++.moderated has a humongous multi-thread conversation on
      this topic. Someone has suggested adding a 'finally' keyword to the
      language.

      I find the idea that anyone thinks C++ can learn something about cleanup
      from Java very disturbing.

      Most sources recommend RAII for C++'s exception-neutral cleanup mechanism.

      --
      Phlip
      http://www.greencheese.org/ZeekLand <-- NOT a blog!!!

      Comment

      • Alf P. Steinbach

        #4
        Re: try/finally implementation in c++

        * avasilev wrote, on 31/03/2006 22:58:[color=blue]
        >
        > I'm curious to see other ideas[/color]

        Disregard the natural language text (if you don't know Norwegian) and
        concentrate on links & code:

        <url: http://utvikling.com/cppfaq/04/04/02/index.html>.

        --
        A: Because it messes up the order in which people normally read text.
        Q: Why is it such a bad thing?
        A: Top-posting.
        Q: What is the most annoying thing on usenet and in e-mail?

        Comment

        • Howard

          #5
          Re: try/finally implementation in c++


          "Phlip" <phlip2005@gmai l.com> wrote in message
          news:KTgXf.1033 $mu2.924@newssv r24.news.prodig y.net...[color=blue]
          > avasilev wrote:
          >[color=green]
          >> I'm curious to see other ideas[/color]
          >
          > news:comp.lang. c++.moderated has a humongous multi-thread conversation on
          > this topic. Someone has suggested adding a 'finally' keyword to the
          > language.
          >
          > I find the idea that anyone thinks C++ can learn something about cleanup
          > from Java very disturbing.
          >[/color]

          Could be a Pascal programmer... using try..finally was a standard way to do
          things in Delphi.

          But I think it's _always_ possible to learn from other languages. (Of
          course, sometimes you just learn what's NOT so good, though...) :-)
          [color=blue]
          > Most sources recommend RAII for C++'s exception-neutral cleanup mechanism.[/color]

          Yep. (But it's a bit of a pain sometimes to make a new class just to handle
          what would only be a couple extra lines of code (i.e., the try/finally
          keywords), if C++ _were_ to implement it.) Still, I'd agree that RAII is
          probably the best solution, at least currently.

          -Howard


          Comment

          • avasilev

            #6
            Re: try/finally implementation in c++

            Yes, this is something I have thought about. The problem is that it is
            quite slow. Imagine that this code executes in a loop - every time it
            will throw two exceptions, depending on the compiler/runtime this could
            execute terribly slow.

            Comment

            • belvis@pacbell.net

              #7
              Re: try/finally implementation in c++

              avasilev wrote:[color=blue]
              > {
              > MyBaseException * handledExceptio n = NULL;
              > try
              > {
              > <try code>
              > }
              > catch(MyBaseExc eption& e)
              > {
              > handledExceptio n = e.Clone();
              > }
              >
              > <finally code>
              >
              > if (handledExcepti on)
              > throw *handledExcepti on;
              > }
              >
              > However, this method has the limitation that it works only for specific
              > classes of exception objects.[/color]

              It also has the limitation of leaking memory from every try/catch block
              whenever it catches an exception, unless you've got some mechanism for
              telling a catch handler to delete the exception.

              Bob

              Comment

              • avasilev

                #8
                Re: try/finally implementation in c++

                It's true, I have programmed in Delphi a lot, but I am not trying to
                make C++ behave like Delphi. One of the reasons for which I like C++ is
                that it gives a lot more freedom. However, I think particularly this
                issue does the opposite - limits your freedom - RAII is not universal.
                Sometimes it is hard/ugly to encapsulate everything that has to be
                cleaned up in one class, so that the destructor can access it. For
                example - when some of the resources are already encapsulated more
                appropriately in other classes. Then the solution would be either to
                redesign the whole class structure artificially so that RAII can be
                applied, thus screwing up the design for the sake of RAII. The other
                approach could be to pass references to external resources to the
                object so that the constructor/destructor can acces it. So I think
                forcing the use of RAII and claiming that it is the ultimate solution
                in all cases is not in the C++ spirit.

                Comment

                • Phlip

                  #9
                  Re: try/finally implementation in c++

                  avasilev wrote:
                  [color=blue]
                  > So I think
                  > forcing the use of RAII and claiming that it is the ultimate solution
                  > in all cases is not in the C++ spirit.[/color]

                  I'm not sure who you reply to, but I didn't claim RAII is ultimate. I think
                  block closures are, but we won't see those in C++ for a while.

                  Consider this C++ -like code:

                  Foo()
                  {
                  Bar aBar;
                  aBar.dirty();
                  finally:
                  aBar.clean();
                  }

                  Implement 'finally' as you like - as a keyword, or a catch().

                  The problem with that code is it couples Bar's private internal state to
                  Foo. If you change how dirty Bar gets, you must find every client of Bar
                  and upgrade the finally block. Bar's cleaness should be a private,
                  encapsulated detail.
                  [color=blue]
                  > Sometimes it is hard/ugly to encapsulate everything that has to be
                  > cleaned up in one class, so that the destructor can access it.[/color]

                  And sometimes that is a sign that the client function (Foo()) is doing too
                  much, and it needs its statements refactored into Bar classes, to
                  encapsulate everything about them, not just how they clean up.

                  --
                  Phlip
                  http://www.greencheese.org/ZeekLand <-- NOT a blog!!!

                  Comment

                  • avasilev

                    #10
                    Re: try/finally implementation in c++

                    Philip, sorry for the misunderstandin g. What i meant was that the
                    language forces you to use RAII, and indirectly (or maybe directly, I
                    remember reading answers to language extension proposals) the C++
                    standards committee thus claims it is _the_ way to do things.
                    I agree that the code you give as an example has this problem. In this
                    case RAII is more appropriate. There is the problem for exposing
                    internal state, but if the onterface of the resource is designed and
                    implemented correctly, then this should not be an issue.
                    Often there is not just one line of code that has to be executed in
                    finally, and not referring to only one resourece. There could be many
                    finally blocks in different parts of the application, referring to same
                    resources. The semantics of the blocks could no be just "cleanup",
                    could be more complicated - e.g. signalling events etc. Probably it
                    could always be implemented with RAII, but this can be a pain and can
                    complicate things.

                    Alex

                    Comment

                    • Kaz Kylheku

                      #11
                      Re: try/finally implementation in c++

                      avasilev wrote:[color=blue]
                      > Hi all
                      >
                      > Its one of my little pragramming challenges to implement a try/finally
                      > construct in C++. I have done several implementations but they all have
                      > limitations.[/color]

                      An unwind protect mechanism is architectural. If it's not in the
                      substrate, it may be impossible to implement 100%. There are semantic
                      pieces in C++ that could do the job, but the syntactic abstraction
                      isn't there.
                      [color=blue]
                      > I'm curious to see other ideas[/color]

                      Firstly, separate the finally mechanism from try and catch. Conflating
                      them together is an unnecessary Java thing which you don't have to
                      adopt. In some other languages, the mechanism that means "execute this
                      regardless of how this terminates" is a separate construct. Common Lisp
                      calls it unwind-protect, a term that is sometimes used outside of Lisp
                      to refer to any such a mechanism..

                      If you separate it out, you have a simpler job, because your syntax
                      does not have to incorporate catch blocks for exceptions. It has only
                      two pieces: the block that is protected, and the code that is run
                      unconditionally .

                      The problem is that you need the unconditional code in two places:
                      immediately following the protected code (normal return case) and in a
                      catch (...) handler.

                      To do this, you can make the entire code into a giant macro argument,
                      by doing which you end up with something that combines ugly appearance
                      with debugger hostility:

                      #include <iostream>

                      #define ugly_unwind_pro tect(block, cleanup) \
                      try { block } catch (...) { cleanup throw; } cleanup

                      int main()
                      {
                      int x = 3;

                      try {
                      ugly_unwind_pro tect (
                      {
                      throw 42;
                      },
                      {
                      // demonstrate access to locals
                      std::cout << "x = " << x << std::endl;
                      }
                      )
                      } catch (int ex) {
                      // the 42 is caught here
                      std::cout << "ex = " << ex << std::endl;
                      }

                      return 0;
                      }

                      Oh yeah, because statements are passed as a single macro argument,
                      commas in them can cause problems. Try changing it to "throw 0, 42" and
                      see, hahaha. That's only a problem for commas that are not enclosed in
                      parentheses.

                      As you can see, you can get all the functionality of try/catch/finally
                      with try/catch and a separate unwind-protect.

                      Note how the unwind code is duplicated textually in two places. Yuck!

                      Comment

                      Working...