C++ exception handling for Smalltalkers

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

C++ exception handling for Smalltalkers

Bill Schwab-2
Blair,

This is slightly off-topic, but not really given that just about any
Smalltalk needs the occaisional boost from a more staticically-typed
language, and because I have C++ questions that (I suspect) only other
Smalltalkers will understand.  I recently did some C++ programming that
reminded me of my lack of knowledge about/confidence in C++ exception
handling.

You won't like it<g>, but I've been using MinGW lately, falling back on VC++
for things that cause trouble otherwise.  However, most if not all of my
coding experience with C++ excpetions has been with MFC macros.  The C++
books on my shelf at home describe try/catch, but Google searches quickly
turn up different implementations and question the thread safety of at least
some of them.  Is C++ exception handling in chaos, or are the posters
confused?  Do you recommend any particular implementation or know of good
reading on the subject?

Apparently one has the choice to pass exception arguments as pointers vs.
references, and there _must_ be issues with memory management.  Any
recommendations on the best way to proceed?  [See what I mean about having
to ask these questions of Smalltalkers? :)]

What does one do for an analog to #ensure:?  #ifCurtailed:?

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: C++ exception handling for Smalltalkers

David Simmons-2
"Bill Schwab" <[hidden email]> wrote in message
news:b3ofs4$1n9ehh$[hidden email]...

> Blair,
>
> This is slightly off-topic, but not really given that just about any
> Smalltalk needs the occaisional boost from a more staticically-typed
> language, and because I have C++ questions that (I suspect) only other
> Smalltalkers will understand.  I recently did some C++ programming that
> reminded me of my lack of knowledge about/confidence in C++ exception
> handling.
>
> You won't like it<g>, but I've been using MinGW lately, falling back on
VC++
> for things that cause trouble otherwise.  However, most if not all of my
> coding experience with C++ excpetions has been with MFC macros.  The C++
> books on my shelf at home describe try/catch, but Google searches quickly
> turn up different implementations and question the thread safety of at
least

> some of them.  Is C++ exception handling in chaos, or are the posters
> confused?  Do you recommend any particular implementation or know of good
> reading on the subject?
>
> Apparently one has the choice to pass exception arguments as pointers vs.
> references, and there _must_ be issues with memory management.  Any
> recommendations on the best way to proceed?  [See what I mean about having
> to ask these questions of Smalltalkers? :)]
>
> What does one do for an analog to #ensure:?  #ifCurtailed:?

Hi Bill,

I regularly use C++ exceptions [and Window SEH and .NET mechanisms] in
addition to those within Smalltalk/S#.

Standard c++ does not provide for the notion of "resumable" exceptions, VC++
using the underlying Microsoft SEH (structured exception handle) platform
model does provide this support.

The S# language implementation (Smalltalk design) is layered on the SEH
model (with some optimizations), which means you can catch any exception
(Smalltalk or otherwise) and manage it. [sorry for the little S# commentary,
but it was worth noting].

In standard c++, once the exception "hander" has been invoked for a
particular "guard" expression, all intervening method frames (from the point
of the exception on up the stack to the guarded-method frame) have
effectively been unwound already [see temporal-issues questions regarding
c++ standard at the end].

In c++ (as you know) the full expression form is:

    try
    {
    }
    catch("guard filter expression => var-type + optionally a var")
    {
        "handler code"
    }

In VC++ we can use the extended forms:

    __try
    {
    }
    __except(ExceptionFilter(GetExceptionInformation()))
    {
    }
    __finally
    {
    }

The extended form in vc++ allows us to provide a function for the
"guard-filter". That filter serves two purposes. First it allows us to
algorithmically take action regarding the "Signal/Warning/Exception" before
the frames between the faulting method and the guard have been unwound, and
it allows us to tell the exception mechanism what to do once our filter is
finished.

I.e., resume-execution, continue-looking-for-a-suitable-handler,
stop-and-call-my-handler.

Which means that (resumable) Smalltalk style exception handling is actually
implemented in the vc++/SEH style "guard-filter" itself, whereas c++
handling is implemented in the "handler" block of SEH behavior.

The second thing we notice about the extended form is that we have a
"finally" clause which is used to declare code we want to have executed
whenever the "try" block finishes "OR" is prematurely terminated due to an
exception fault unwinding it.

So, to distinguish between a "curtailed" and a "non-curtailed" Smalltalk
style exception unwind we would have to add a little to the sequence.
    bool wasCurtailed = true;
    __try
    {
        ... our try body here ...

        wasCurtailed = false;
    }
    __except(ExceptionFilter(GetExceptionInformation()))
    {
    }
    __finally
    {
        if(wasCurtailed)
           ...
        else
           ...
    }

I should also add that all versions of XP and later provide for dynamic SEH
exception filters (first chance filters) which can be registered on a thread
and will come ahead of normally stack-discipline exception guards. This
latter capability is very useful for many operations where you need to
handle/hide extrinsically triggered exceptions which c++ model code cannot
deal with. I should also point out that c++ only traps c++ exceptions,
whereas the VC++ extended form allows capturing of signals, warnings,
exceptions etc which includes interrupts (including INT3/DebugBreak),
faults, and the like.

Microsoft's .NET CLR (common language runtime) mechanisms are fairly similar
to the SEH model except (for non-specific reasons) the guard-filter does not
support "resume-execution" semantics.

>From .NET IL we have:

    .try <il_start_range> to <il_end_range>
         filter <il_filter_label>
             handler <il_start_range> to <il_end_range>
         // catch "<type> handler ..." are optional here
         finally
             handler <il_start_range> to <il_end_range>
         fault
             handler <il_start_range> to <il_end_range>.

Generally coded as:

   .try
    {
        ...
    }
    filter
    {
        ...
        endfilter
    } "handler" {
        ...
    }
    finally
    {
        ...
    }
    fault
    {
        ...
    }

This effectively corresponds to S# equivalents of the form:

    try [
    ]
    "we can have multiple catch clauses and discrete handlers here"
    catch("filter-expression including closures etc") [
        "handler is executed during the filter"
        "if recoded in .NET/VC++ handler body is no-op"
    ]
    finally [
    ]
    fault "or ifCurtailed" [
    ].

Where the keyword variable <thisSignal> can be referenced where needed, or a
variable to hold <thisSignal> can be declared as a parameter to a handler
block.

The (typically less-efficient/more-cumbersome-nesting) classic resumable
ANSI Smalltalk exceptions subset of the above would look like:

    [
        [
            [
                ...place actual try body here...
            ]
            on: exceptionFilter do: [:signal|
                ...exception handler body...
            ].
        ]
        ifCurtailed: [:signal|
            ...curtailed/fault handler body...
        ]
     ]
     ensure: [:signal|
         ...finally handler body...
     ].

As to the question of "pointer" versus "new-inst" form with exceptions, you
do need to be careful. It really helps to understand the temporal semantics
in question for c++ [which, as I now realize in writing this -- see below --
I am not so sure about].
Which is that the given exception-handler is logically invoked "after" all
the intervening frames have been unwound. In practice they will probably not
have been unwound yet (come to think about it, I'm sure the c++ spec must
say something about this timing).

What that means is that it is probably safe to use an "auto/stack" allocated
exception in a throw since the stack has not actually been unwound when the
guard is invoked. But if stack unwind semantics (maybe specified in C++
standard) result in the destructor being called on the (auto/stack)
allocated exception before you get it, then you are getting an exception
structure whose memory still exists but which has already had its destructor
invoked. I.e., generally the destructors in an exception do nothing so this
is a non-issue.

I could go look at the c++ spec/tome for clarification, but I will leave
this to someone with a bit more time for such digging.

Cheers,

-- Dave S. [www.smallscript.org]

>
> Have a good one,
>
> Bill
>
> --
> Wilhelm K. Schwab, Ph.D.
> [hidden email]
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: C++ exception handling for Smalltalkers

Randy Coulman-2
In reply to this post by Bill Schwab-2
Ahh, a question I feel remotely qualified to answer :-).

Bill Schwab wrote:

>
> You won't like it<g>, but I've been using MinGW lately, falling back on VC++
> for things that cause trouble otherwise.  However, most if not all of my
> coding experience with C++ excpetions has been with MFC macros.  The C++
> books on my shelf at home describe try/catch, but Google searches quickly
> turn up different implementations and question the thread safety of at least
> some of them.  Is C++ exception handling in chaos, or are the posters
> confused?  Do you recommend any particular implementation or know of good
> reading on the subject?
>

Probably the best reading on exceptions in C++ are Herb Sutter's two
books (Exceptional C++ and More Exceptional C++), which are expanded
versions of his various C++ Guru of the Week articles posted on the net
over the years.  I haven't actually read the books, but I hear they are
quite good.  He talks especially about writing classes that are
exception safe.  There's beginning to be a good corpus of knowledge
about how to do that.

> Apparently one has the choice to pass exception arguments as pointers vs.
> references, and there _must_ be issues with memory management.  Any
> recommendations on the best way to proceed?  [See what I mean about having
> to ask these questions of Smalltalkers? :)]
>

According to Scott Meyers' _More_Effective_C++_ Item 13: "Catch
exceptions by reference".  He goes into a lot of detail about why.  In a
nutshell, catching by value can cause "slicing" of the exception type
(catching a base exception object by value when a derived exception
object was thrown) and catching by pointer brings up object lifetime
issues as you suspect.

If you're writing a lot of C++ code, I'd recommend Scott's books
(Effective C++, More Effective C++, and Effective STL).  He's got a CD
out that has the first two plus some bonus material.  In my opinion,
he's done a really nice job with the CD version - searchable, good
cross-references, etc.

> What does one do for an analog to #ensure:?  #ifCurtailed:?
>

C++ has an idiom that is worth knowing here.  It's relatively unique to
C++ because it can't effectively be done in a garbage collected language
(due to the non-determinism involved in when or if objects will get
finalized).  The idiom is called, for reasons I don't really understand,
"Resource Acquisition is Initialization" or RAII for short.

Basically, the idea is that the stuff that you would normally put in an
#ensure: or finally clause in Smalltalk or Java respectively goes into a
destructor in C++.  Often, you will introduce small classes for this,
and you may resist that at first.  However, I find that it really helps
my code a lot when I do this.

C++ smart pointers are examples of this idiom, and you can do similar
things when acquiring any external resource (locks in multi-threading
code, handles in Windows, file handling, etc.).  By reading Herb
Sutter's stuff, you'll find that this idiom is one of the techniques at
the heart of writing exception-safe code without needing to catch a lot
of exceptions.  I find in my code that I pretty much never have to worry
about memory or other resource leaks in my code, and the code reads much
better as a bonus.

Another advantage is that it means that clients of your code (including
your future forgetful self) don't have to remember to call the cleanup
code after every use of your class.

I've never used #ifCurtailed:, but after reading the method comment, I'm
not sure how you could handle the non-local return part of it in C++
(although David Simmons' response mentions an idea).  For anything else,
you would put the code in the catch() clause.

My gut reaction is that I'd try to write code that didn't need
#ifCurtailed:.  Somehow it seems like a bit of a code smell to need that
kind of knowledge.  Yet, browsing through some of the senders of it in
Dolphin, I can see some valid uses for it.

Hope this helps.  Ask for clarification if you need it.

Randy
--
Randy Coulman
NOTE: Reply-to: address is spam-guarded.  Reassemble the following to
reply directly:
rvcoulman at acm dot org