|
Boost : |
From: Andreas Huber (ahd6974-spamgroupstrap_at_[hidden])
Date: 2006-12-23 05:16:14
Andrey Semashev wrote:
>>> As for states' allocation and deallocation, there may be other
>>> issues with it, besides of performance loss. I'm not quite sure you
>>> have read our discussion with Alexander Nasonov in this thread,
>>> where I pointed out that the fact that the state is deleted when
>>> being left may be inconvenient if the state has its local data. If
>>> the state is visited again all these data are lost.
>
>> Right, in my experience this is the behavior that is most commonly
>> wanted. IIUC, what you want is something like the currently supported
>> history but with the added feature that all local variables are also
>> restored upon entry of the state. Such a feature has been suggested
>> before but I've so far not found a satisfying way to implement it.
>> IMO, you definitely need both options and sometimes a state even
>> contains multiple variables with different needs of
>> resetting/reconstitution.
>
> Agreed, that's why I decided not to delete states during transitions.
> If some variables need to be reset when the state is being left, a
> user may implement such logic in the appropriate handler function.
In your library, is there any way to do this automatically, a la RAII?
I'm asking because in my experience, you often need to acquire a
resource upon state entry and release it upon state exit. It's
error-prone when you need to release explicitly, just as it is
error-prone when you need to manually release resources at the end of a
block scope. That's why Boost.Statechart has this strict state-exit to
destructor mapping. If you need a variable to live longer you push it
into an outer state, just as you do with a variable allocated on the
stack when you push it into an outer scope. Yes, this is suboptimal in
the sense that other inner states of the outer state can then also
access said variable, but the same is true for stack variables.
> Just a thought of similar functionality support in Statechart. If
> there was an additional optional template parameter in the "state" or
> "simple_state" class template that would have a type of the state's
> context which lifetime would last from the first entrance into the
> state until the whole state machine destruction (let's call it a
> static state context), then a reference to the context might have been
> passed to the state's constructor. For example:
>
> // This will be the static context
> struct State1Ctx
> {
> int n;
> };
>
> struct State1 :
> public sc::simple_state< State1, OuterState, State1Ctx >
> {
> // This reference will hold the context
> State1Ctx& static_ctx_;
>
> // In ctor we receive a reference to the static context.
> // No matter how many times we enter the state,
> // we get the reference to the same object here
> State1(State1Ctx& ctx) : static_ctx_(ctx) { }
> };
>
> Or, alternatively, the static_ctx_ reference may even be in the
> "simple_state" class itself. It may be accessible via some public
> method.
I'd hate to add yet another template parameter, but the same could be
achieved via specializations of a template (suggested long ago by Dave
Abrahams):
In simple-state.hpp:
template<class State>
class private_state_context {}; // Probably needs a better name
template< class MostDerived, ... >
class simple_state
{
// ...
private_state_context< MostDerived > & private_context();
const private_state_context< MostDerived > & private_context() const;
// ...
};
If a user needs a private context for a state, she can specialize the
private_state_context template for said state. It should be pretty easy
to add something like this. The only problem is that every added feature
also increases the opportunities for abuse and confusion. I'll think
about this some more and then maybe add it to the to-do list.
>>> Additionally as the data
>>> amount and states number raises the code of these data-holding
>>> classes gets more messy.
>
>> You've lost me here: Which data-holding classes? In Boost.Statechart
>> there are only states.
>
> By "data-holding classes" I meant collectively states and the state
> machine classes that can hold data of inner states that we were
> discussing above.
Ok.
> I was saying that as the amount of states grows so
> does the amount of data. And if it is stored in some outer state, the
> state becomes overweightened and messy.
I agree for the cases when you need to push outward a variable due to
lifetime-issues only (i.e. the variable is still only accessed by the
state that originally contained it). However, IME, outer states are
almost never pure data holding classes, they *usually* have behavior of
their own and often need to access precisely the variables that were
pushed outward from inner states (e.g. see the Stopwatch example).
> To my mind this issue should
> be of special concern since Statechart is more targeted to creation of
> bigger state machines.
It has been a concern, I'm just unsure how it is best solved.
>>> BTW, is there any way to make Boost.Statechart's machine not
>>> compiling if it doesn't expect some particular event type? IOW, to
>>> force the machine to support all event types being passed to it?
>
>> No, as that would require the implementation of the whole machine in
>> one TU. IMO, the ability to compile parts of a large machine
>> separately is more important in practice.
>
> Ah, that's right. Modularity takes its toll.
Precisely, as do many other features. I have to accept that the library
cannot satisfy all needs, e.g. especially parser-like FSMs are better
implemented by other means.
Regards,
-- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk