mirror of
https://github.com/boostorg/statechart.git
synced 2026-01-23 18:12:11 +00:00
264 lines
9.6 KiB
HTML
264 lines
9.6 KiB
HTML
<html>
|
|
|
|
<head>
|
|
<meta http-equiv="Content-Language" content="en-us">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
|
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
<link rel="stylesheet" type="text/css" href="../../../boost.css">
|
|
<title>The boost::fsm library - FAQ</title>
|
|
</head>
|
|
|
|
<body link="#0000ff" vlink="#800080">
|
|
|
|
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary="header">
|
|
<tr>
|
|
<td valign="top" width="300">
|
|
<h3><a href="../../../index.htm">
|
|
<img alt="C++ Boost" src="../../../c++boost.gif" border="0" width="277" height="86"></a></h3>
|
|
</td>
|
|
<td valign="top">
|
|
<h1 align="center">The boost::fsm library</h1>
|
|
<h2 align="center">Frequently Asked Questions (FAQs)</h2>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<hr>
|
|
<dl class="page-index">
|
|
<dt><a href="#Does boost::fsm support polymorphic events">Does boost::fsm
|
|
support polymorphic events?</a></dt>
|
|
<dt>
|
|
<a href="#How can I hide the inner workings of a state machine from its clients">
|
|
How can I hide the inner workings of a state machine from its clients?</a></dt>
|
|
<dt>
|
|
<a href="#Is it possible to inherit from a given state machine and modify its layout in the subclass">
|
|
Is it possible to inherit from a given state machine and modify its layout
|
|
in the subclass?</a></dt>
|
|
<dt>
|
|
<a href="#Why are exit-actions called in the wrong order when I use multiple inheritance">
|
|
Why are exit-actions called in the wrong order when I use multiple
|
|
inheritance?</a></dt>
|
|
</dl>
|
|
<h2><a name="Does boost::fsm support polymorphic events">Does boost::fsm
|
|
support polymorphic events?</a></h2>
|
|
<p>No. Although events can be derived from each other to write common code
|
|
only once, <a href="definitions.html#Reaction">reactions</a> can only be
|
|
defined for most-derived events.</p>
|
|
<p>Example:</p>
|
|
<pre>template< class MostDerived >
|
|
struct EvButtonPressed : fsm::event< MostDerived >
|
|
{
|
|
// common code
|
|
};
|
|
|
|
struct EvPlayButtonPressed :
|
|
EvButtonPressed< EvPlayButtonPressed > {};
|
|
struct EvStopButtonPressed :
|
|
EvButtonPressed< EvStopButtonPressed > {};
|
|
struct EvForwardButtonPressed :
|
|
EvButtonPressed< EvForwardButtonPressed > {};
|
|
|
|
/* ... */
|
|
|
|
// We want to turn the player on, no matter what button we
|
|
// press in the Off state. Although we can write the reaction
|
|
// code only once, we must mention all most-derived events in
|
|
// the reaction list.
|
|
struct Off : fsm::simple_state< Off, Mp3Player, mpl::list<
|
|
fsm::custom_reaction< EvPlayButtonPressed >,
|
|
fsm::custom_reaction< EvStopButtonPressed >,
|
|
fsm::custom_reaction< EvForwardButtonPressed > > >
|
|
{
|
|
template< class MostDerived >
|
|
fsm::result react( const EvButtonPressed< MostDerived > & )
|
|
{
|
|
// ...
|
|
}
|
|
};</pre>
|
|
<h2>
|
|
<a name="How can I hide the inner workings of a state machine from its clients">
|
|
How can I hide the inner workings of a state machine from its clients?</a></h2>
|
|
<p>To see why and how this is possible it is important to recall the following
|
|
facts:</p>
|
|
<ul>
|
|
<li>Member functions of a C++ class template are instantiated at the point
|
|
where they're actually called. If the function is never called, it will not
|
|
be instantiated and not a single assembly instruction will ever be
|
|
generated.</li>
|
|
<li>The <code>InitialState</code> template parameter of <code>
|
|
fsm::state_machine</code> can be an incomplete type (i.e. forward declared).</li>
|
|
</ul>
|
|
<p>The class template member function <code>state_machine<>::initiate()</code>
|
|
creates an object of the initial state. So, the definition of this state must
|
|
be known before the compiler reaches the point where <code>initiate()</code>
|
|
is called. To be able to hide the initial state of a state machine in a .cpp
|
|
file we must therefore no longer let clients call <code>initiate()</code>.
|
|
Instead, we do so in the .cpp file, at a point where the full definition of
|
|
the initial state is known.</p>
|
|
<p>Example:</p>
|
|
<p>StopWatch.hpp:</p>
|
|
<pre>// define events ...
|
|
|
|
struct Active; // the only visible forward
|
|
struct StopWatch : fsm::state_machine< StopWatch, Active >
|
|
{
|
|
StopWatch();
|
|
};</pre>
|
|
<p>StopWatch.cpp:</p>
|
|
<pre>struct Stopped;
|
|
struct Active : fsm::simple_state< Active, StopWatch,
|
|
fsm::transition< EvReset, Active >, Stopped > {};
|
|
struct Running : fsm::simple_state< Running, Active,
|
|
fsm::transition< EvStartStop, Stopped > > {};
|
|
struct Stopped : fsm::simple_state< Stopped, Active,
|
|
fsm::transition< EvStartStop, Running > > {};
|
|
|
|
StopWatch::StopWatch()
|
|
{
|
|
// For example, we might want to ensure that the state
|
|
// machine is already started after construction.
|
|
// Alternatively we could also provide the client with
|
|
// a Start() function...
|
|
<b>initiate();</b>
|
|
}</pre>
|
|
<h2>
|
|
<a name="Is it possible to inherit from a given state machine and modify its layout in the subclass">
|
|
Is it possible to inherit from a given state machine and modify its layout in
|
|
the subclass?</a></h2>
|
|
<p>Yes, but contrary to what some FSM code generators allow, boost::fsm
|
|
machines can do so only in a way that was foreseen by the designer of the base
|
|
state machine: </p>
|
|
<pre>struct EvStart : fsm::event< EvStart > {};
|
|
|
|
struct Idle;
|
|
struct PumpBase : fsm::state_machine< PumpBase, Idle >
|
|
{
|
|
<b>virtual fsm::result react(
|
|
</b> <b>Idle & idle, const EvStart & ) const;
|
|
</b>};
|
|
|
|
struct Idle : fsm::simple_state< Idle, PumpBase,
|
|
fsm::custom_reaction< EvStart > >
|
|
{
|
|
fsm::result react( const EvStart & evt )
|
|
{
|
|
<b>return context< PumpBase >().react( *this, evt );</b>
|
|
}
|
|
};
|
|
|
|
struct Running : fsm::simple_state< Running, PumpBase > {};
|
|
|
|
fsm::result PumpBase::react(
|
|
Idle & idle, const EvStart & ) const
|
|
{
|
|
<b>return idle.transit< Running >();
|
|
</b>}
|
|
|
|
|
|
struct MyRunning : fsm::simple_state< MyRunning, PumpBase > {};
|
|
|
|
struct MyPump : PumpBase
|
|
{
|
|
virtual fsm::result react(
|
|
Idle & idle, const EvStart & ) const
|
|
{
|
|
<b>return idle.transit< MyRunning >();
|
|
</b> }
|
|
};</pre>
|
|
<h2>
|
|
<a name="Why are exit-actions called in the wrong order when I use multiple inheritance">
|
|
Why are exit-actions called in the wrong order when I use multiple
|
|
inheritance?</a></h2>
|
|
<p>They definitely aren't for the <code>simple_state</code> and <code>state</code>
|
|
subclasses, but the destructors of additional bases might be called in
|
|
construction order (rather than the reverse construction order):</p>
|
|
<pre>#include <boost/fsm/state_machine.hpp>
|
|
#include <boost/fsm/simple_state.hpp>
|
|
|
|
namespace fsm = boost::fsm;
|
|
|
|
class EntryExitDisplayer
|
|
{
|
|
protected:
|
|
EntryExitDisplayer( const char * pName ) :
|
|
pName_( pName )
|
|
{
|
|
std::cout << pName_ << " entered\n";
|
|
}
|
|
|
|
~EntryExitDisplayer()
|
|
{
|
|
std::cout << pName_ << " exited\n";
|
|
}
|
|
|
|
private:
|
|
const char * const pName_;
|
|
};
|
|
|
|
struct Outer;
|
|
struct Machine : fsm::state_machine< Machine, Outer > {};
|
|
struct Inner;
|
|
struct Outer : EntryExitDisplayer, fsm::simple_state<
|
|
Outer, Machine, fsm::no_reactions, Inner >
|
|
{
|
|
Outer() : EntryExitDisplayer( "Outer" ) {}
|
|
};
|
|
|
|
struct Inner : EntryExitDisplayer,
|
|
fsm::simple_state< Inner, Outer >
|
|
{
|
|
Inner() : EntryExitDisplayer( "Inner" ) {}
|
|
};
|
|
|
|
int main()
|
|
{
|
|
Machine myMachine;
|
|
myMachine.initiate();
|
|
return 0;
|
|
}</pre>
|
|
<p>This program will produce the following output:</p>
|
|
<pre>Outer entered
|
|
Inner entered
|
|
Outer exited
|
|
Inner exited</pre>
|
|
<p>That is, the <b><code>EntryExitDisplayer</code> base class portion</b> of
|
|
<code>Outer</code> is destructed before the one of <code>Inner</code> although
|
|
<code>Inner::~Inner()</code> is called before <code>Outer::~Outer()</code>.
|
|
This somewhat counter-intuitive behavior is caused by the following facts: </p>
|
|
<ul>
|
|
<li>The <code>simple_state<></code> base class portion of <code>Inner</code>
|
|
is responsible to destruct <code>Outer</code></li>
|
|
<li>Destructors of base class portions are called in the reverse order of
|
|
construction</li>
|
|
</ul>
|
|
<p>So, when the <code>Outer</code> destructor is called the call stack looks
|
|
as follows:</p>
|
|
<pre>Outer::~Outer()
|
|
simple_state< Inner, ... >::~simple_state()
|
|
Inner::~Inner()</pre>
|
|
<p>Note that <code>Inner::~Inner()</code> did not yet have a chance to destroy
|
|
its <code>EntryExitDisplayer</code> base class portion, as it first has to
|
|
call the destructor of the <b>second</b> base class. Now <code>Outer::~Outer()</code>
|
|
will first destruct its <code>simple_state< Outer, ... ></code> base class
|
|
portion and then do the same with its <code>EntryExitDisplayer</code> base
|
|
class portion. The stack then unwinds back to <code>Inner::~Inner()</code>,
|
|
which can then finally finish by calling <code>
|
|
EntryExitDisplayer::~EntryExitDisplayer()</code>.</p>
|
|
<p>Luckily, there is an easy work-around: Always let <code>simple_state<></code>
|
|
and <code>state<></code> be the first base class of a state. This ensures that
|
|
destructors of additional bases are called before recursion employed by state
|
|
base destructors can alter the order of destruction.</p>
|
|
<hr>
|
|
<p>Revised
|
|
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan -->11 January, 2004<!--webbot bot="Timestamp" endspan i-checksum="38695" --></p>
|
|
<p><i>Copyright © <a href="mailto:ah2003@gmx.net">Andreas Huber Dönni</a>
|
|
2003-2004. Use, modification and distribution are subject to the Boost
|
|
Software License, Version 1.0. (See accompanying file
|
|
<a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at
|
|
<a href="http://www.boost.org/LICENSE_1_0.txt">
|
|
http://www.boost.org/LICENSE_1_0.txt</a>)</i></p>
|
|
|
|
</body>
|
|
|
|
</html>
|