Boost logo

Boost :

From: Andreas Huber (ah2003_at_[hidden])
Date: 2004-05-23 05:32:16


Hi Dave,

[snip]
> After a brief glance, it looks like a very sophisticated and
> well-thought-out library.

Thanks :-)

> I'd like to know if following state
> transitions require dynamic allocation or not.

By default (i.e. when you define states as demonstrated in the tutorial), a
dynamic allocation happens in the course of every state entry. However,
since users define all state classes themselves, they have full control over
how each state will be allocated (see "Memory management customization" in
the rationale).

[snip]
>> Exception handling
>> ------------------
>>
>> Exceptions can be propagated from all user code except from state
>> exit actions (mapped to destructors and destructors should virtually
>> never throw in C++).
>
> That seems like a bad limitation, and for me it calls into question
> the idea of mapping state exit to destructors. Can you explain why
> that's the right design?

Yes, there's a lot of evidence that state exit actions must not fail:

Say you have a state_machine<> subclass S and an object of that class, which
currently resides in state A and state B nested in A (see the picture under
Error handling in ratinale.html). Inside S::~S, the state machine is
terminated what leads to the exit actions of B and A being executed. If B's
exit action fails, what can you do with the resulting exception? I guess we
agree that you cannot propagate it out of S::~S. I think we also agree that
despite the failure in B's exit action, we must still execute A's exit
action before returning from S::~S. W.r.t. to handling said exception I
believe that at this point there's pretty much nothing that can be done by
the caller of B's exit action that couldn't be done inside the exit action
before returning to its caller. That is, in this particular situation,
there's no point in propagating an exception from B's exit action.
I agree that this is a rather special situation, because exit actions are
called from a destructor. However, even if exit actions are called in the
course of a normal transition what are you going to do if B's exit action
throws an exception? Technically, the state machine still resides in B, so
you have pretty few options for continuing. You cannot exit A as that would
violate the state machine invariant that inner states are always exited
before outer states. You cannot make a transition to another state, as that
would also require successful exit from B. So, the only sensible thing is to
try to handle the error inside B's exit action. If the error cannot be
handled there it must either be ignored or, in the case of a really serious
error, be handled with a different mechanism than exceptions.

>> Out of the box, state_machine<> does the following:
>>
>> 1. The exception is caught
>
> By the state machine framework?

Yes.

>
>> 2. In the catch block, an exception_thrown event is allocated on the
>> stack
>>
>> 3. Also in the catch block, an immediate dispatch of the
>> exception_thrown event is attempted.
>
> Hum. So basically, any throwing code that could be invoked from
> processing exception_thrown and from processing some other event had
> better be re-entrant?

Yes. However, I don't think this will happen in practice. Code that is
executed as a result of the processing of an exception_thrown event is
typically very different from code that is executed during normal state
machine operation. Moreover, if code reacting to an exception_thrown event
throws itself an exception then this exception will under all circumstances
be propagated to the state machine client. That is, error handling code does
not have to be reentrant.

>> That is, possibly remaining events in the queue are dispatched
>> only after the exception has been handled successfully
>
> I don't understand the relationship here.

A state machine can post internal events (simple_state<>::post_event())
while processing an event. Those internal events are pushed into a queue and
processed as soon as the state machine has finished processing the current
event. If an exception is thrown while processing any of these events, the
resulting exception_thrown event "overtakes" the still queued events.

>> 4. If the exception was handled successfully
>
> What does that mean? Who signals "successful handling", and how do
> they do it?

This is explained a bit further down under the title Successful exception
handling. I agree that this is probably a bit hard to find. I've added a
link in my version.

Regards,

Andreas


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