• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
3<html>
4<head>
5  <meta http-equiv="Content-Language" content="en-us">
6  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
7  <meta name="GENERATOR" content="Microsoft FrontPage 6.0">
8  <meta name="ProgId" content="FrontPage.Editor.Document">
9  <link rel="stylesheet" type="text/css" href="../../../boost.css">
10
11  <title>The Boost Statechart Library - FAQ</title>
12</head>
13
14<body link="#0000FF" vlink="#800080">
15  <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
16  "header">
17    <tr>
18      <td valign="top" width="300">
19        <h3><a href="../../../index.htm"><img alt="C++ Boost" src=
20        "../../../boost.png" border="0" width="277" height="86"></a></h3>
21      </td>
22
23      <td valign="top">
24        <h1 align="center">The Boost Statechart Library</h1>
25
26        <h2 align="center">Frequently Asked Questions (FAQs)</h2>
27      </td>
28    </tr>
29  </table>
30  <hr>
31
32  <dl class="page-index">
33    <dt><a href="#StateLocalStorage">What's so cool about state-local
34    storage?</a></dt>
35
36    <dt><a href="#HideInnerWorkings">How can I hide the inner workings of a
37    state machine from its clients?</a></dt>
38
39    <dt><a href="#MachineInheritance">Is it possible to inherit from a given
40    state machine and modify its layout in the subclass?</a></dt>
41
42    <dt><a href="#Uml2">What about UML2.0 features?</a></dt>
43
44    <dt><a href="#AssertInStateDestructor">Why do I get an assert when I
45    access the state machine from a state destructor?</a></dt>
46
47    <dt><a href="#EmbeddedApplications">Is Boost.Statechart suitable for
48    embedded applications?</a></dt>
49
50    <dt><a href="#HardRealtime">Is your library suitable for applications
51    with hard real-time requirements?</a></dt>
52
53    <dt><a href="#TemplatedStates">With templated states I get an error that
54    'inner_context_type' is not defined. What's wrong?</a></dt>
55
56    <dt><a href="#CompilerError">My compiler reports an error in the library
57    code. Is this a bug in Boost.Statechart?</a></dt>
58
59    <dt><a href="#DisableHistory">Is it possible to disable history for a
60    state at runtime?</a></dt>
61
62    <dt><a href="#Dll">How can I compile a state machine into a dynamic link
63    library (DLL)?</a></dt>
64
65    <dt><a href="#PolymorphicEvents">Does Boost.Statechart support
66    polymorphic events?</a></dt>
67
68    <dt><a href="#WrongExitActionOrder">Why are exit-actions called in the
69    wrong order when I use multiple inheritance?</a></dt>
70  </dl>
71
72  <h2><a name="StateLocalStorage" id="StateLocalStorage">What's so cool about
73  state-local storage?</a></h2>
74
75  <p>This is best explained with an example:</p>
76  <pre>
77struct Active;
78struct Stopped;
79struct Running;
80struct StopWatch : sc::state_machine&lt; StopWatch, Active &gt;
81{
82  // startTime_ remains uninitialized, because there is no reasonable default
83  StopWatch() : elapsedTime_( 0.0 ) {}
84  ~StopWatch()
85  {
86    terminate();
87  }
88
89  double ElapsedTime() const
90  {
91    // Ugly switch over the current state.
92    if ( state_cast&lt; const Stopped * &gt;() != 0 )
93    {
94      return elapsedTime_;
95    }
96    else if ( state_cast&lt; const Running * &gt;() != 0 )
97    {
98      return elapsedTime_ + std::difftime( std::time( 0 ), startTime_ );
99    }
100    else // we're terminated
101    {
102      throw std::bad_cast();
103    }
104  }
105
106  // elapsedTime_ is only meaningful when the machine is not terminated
107  double elapsedTime_;
108  // startTime_ is only meaningful when the machine is in Running
109  std::time_t startTime_;
110};
111
112struct Active : sc::state&lt; Active, StopWatch, Stopped &gt;
113{
114  typedef sc::transition&lt; EvReset, Active &gt; reactions;
115
116  Active( my_context ctx ) : my_base( ctx )
117  {
118    outermost_context().elapsedTime_ = 0.0;
119  }
120};
121
122  struct Running : sc::state&lt; Running, Active &gt;
123  {
124    typedef sc::transition&lt; EvStartStop, Stopped &gt; reactions;
125
126    Running( my_context ctx ) : my_base( ctx )
127    {
128      outermost_context().startTime_ = std::time( 0 );
129    }
130
131    ~Running()
132    {
133      outermost_context().elapsedTime_ +=
134        std::difftime( std::time( 0 ), outermost_context().startTime_ );
135    }
136  };
137
138  struct Stopped : sc::simple_state&lt; Stopped, Active &gt;
139  {
140    typedef sc::transition&lt; EvStartStop, Running &gt; reactions;
141  };
142</pre>
143
144  <p>This StopWatch does not make any use of state-local storage while
145  implementing the same behavior as the <a href=
146  "tutorial.html#BasicTopicsAStopWatch">tutorial StopWatch</a>. Even though
147  this code is probably easier to read for the untrained eye, it does have a
148  few problems that are absent in the original:</p>
149
150  <ul>
151    <li>This StopWatch class has data members that have a meaningful value
152    only if the state machine happens to be in a certain state. That is, the
153    lifetimes of these variables are not identical with the one of the
154    StopWatch object containing them. Since the lifetimes are managed by the
155    entry and exit actions of states, we need to use an ugly switch over the
156    current state (see <code>StopWatch::ElapsedTime()</code>) if we want to
157    access them from a context where the current state is unclear. This
158    essentially duplicates some of the state logic of the FSM. Therefore,
159    whenever we need to change the layout of the state machine we will likely
160    also need to change the ugly switch. Even worse, if we forget to change
161    the switch, the code will probably still compile and maybe even silently
162    do the wrong thing. Note that this is impossible with the version in the
163    tutorial, which will at least throw an exception and often just refuse to
164    compile. Moreover, for the tutorial StopWatch there's a much higher
165    chance that a programmer will get a change correct the first time since
166    the code that calculates the elapsed time is located close to the code
167    that updates the variables</li>
168
169    <li>We need to change the StopWatch class whenever we want to introduce a
170    new variable or change the type of an already existing variable. That is,
171    many changes in the FSM will likely lead to a change in the StopWatch
172    class. In all FSMs that do not employ state-local storage, the
173    <code>state_machine&lt;&gt;</code> subtype will therefore be a change
174    hotspot, which is a pretty sure indicator for a bad design</li>
175  </ul>
176
177  <p>Both points are not much of a problem in a small example like this,
178  which can easily be implemented in a single translation unit by a single
179  programmer. However, they quickly become a major problem for a big complex
180  machine spread over multiple translation units, which are possibly even
181  maintained by different programmers.</p>
182
183  <h2><a name="HideInnerWorkings" id="HideInnerWorkings">How can I hide the
184  inner workings of a state machine from its clients?</a></h2>
185
186  <p>To see why and how this is possible it is important to recall the
187  following facts:</p>
188
189  <ul>
190    <li>Member functions of a C++ class template are instantiated at the
191    point where they're actually called. If the function is never called, it
192    will not be instantiated and not a single assembly instruction will ever
193    be generated</li>
194
195    <li>The <code>InitialState</code> template parameter of
196    <code>sc::state_machine</code> can be an incomplete type (i.e. forward
197    declared)</li>
198  </ul>
199
200  <p>The class template member function
201  <code>state_machine&lt;&gt;::initiate()</code> creates an object of the
202  initial state. So, the definition of this state must be known before the
203  compiler reaches the point where <code>initiate()</code> is called. To be
204  able to hide the initial state of a state machine in a .cpp file we must
205  therefore no longer let clients call <code>initiate()</code>. Instead, we
206  do so in the .cpp file, at a point where the full definition of the initial
207  state is known.</p>
208
209  <p>Example:</p>
210
211  <p>StopWatch.hpp:</p>
212  <pre>
213// define events ...
214
215struct Active; // the only visible forward
216struct StopWatch : sc::state_machine&lt; StopWatch, Active &gt;
217{
218  StopWatch();
219};
220</pre>
221
222  <p>StopWatch.cpp:</p>
223  <pre>
224struct Stopped;
225struct Active : sc::simple_state&lt; Active, StopWatch, Stopped &gt;
226{
227  typedef sc::transition&lt; EvReset, Active &gt; reactions;
228};
229
230  struct Running : sc::simple_state&lt; Running, Active &gt;
231  {
232    typedef sc::transition&lt; EvStartStop, Stopped &gt; reactions;
233  };
234
235  struct Stopped : sc::simple_state&lt; Stopped, Active &gt;
236  {
237    typedef sc::transition&lt; EvStartStop, Running &gt; reactions;
238  };
239
240StopWatch::StopWatch()
241{
242  // For example, we might want to ensure that the state
243  // machine is already started after construction.
244  // Alternatively, we could add our own initiate() function
245  // to StopWatch and call the base class initiate() in the
246  // implementation.
247  <b>initiate();</b>
248}
249</pre>
250  <p>The PingPong example demonstrates how the inner workings of an
251  asynchronous_state_machine<> subclass can be hidden.</p>
252
253  <h2><a name="MachineInheritance" id="MachineInheritance">Is it possible to
254  inherit from a given state machine and modify its layout in the
255  subclass?</a></h2>
256
257  <p>Yes, but contrary to what some FSM code generators allow,
258  Boost.Statechart machines can do so only in a way that was foreseen by the
259  designer of the base state machine:</p>
260  <pre>
261struct EvStart : sc::event&lt; EvStart &gt; {};
262
263struct Idle;
264struct PumpBase : sc::state_machine&lt; PumpBase, Idle &gt;
265{
266  <b>virtual sc::result react(
267</b>    <b>Idle &amp; idle, const EvStart &amp; ) const;
268</b>};
269
270struct Idle : sc::simple_state&lt; Idle, PumpBase &gt;
271{
272  typedef sc::custom_reaction&lt; EvStart &gt; reactions;
273
274  sc::result react( const EvStart &amp; evt )
275  {
276    <b>return context&lt; PumpBase &gt;().react( *this, evt );</b>
277  }
278};
279
280struct Running : sc::simple_state&lt; Running, PumpBase &gt; {};
281
282sc::result PumpBase::react(
283  Idle &amp; idle, const EvStart &amp; ) const
284{
285  <b>return idle.transit&lt; Running &gt;();
286</b>}
287
288
289struct MyRunning : sc::simple_state&lt; MyRunning, PumpBase &gt; {};
290
291struct MyPump : PumpBase
292{
293  virtual sc::result react(
294    Idle &amp; idle, const EvStart &amp; ) const
295  {
296    <b>return idle.transit&lt; MyRunning &gt;();
297</b>  }
298};
299</pre>
300
301  <h2><a name="Uml2" id="Uml2">What about UML 2.0 features?</a></h2>
302
303  <p>The library was designed before 2.0 came along. Therefore, if not
304  explicitly noted otherwise, the library implements the behavior mandated by
305  the UML1.5 standard. Here's an incomplete list of differences between the
306  2.0 semantics &amp; Boost.Statechart semantics:</p>
307
308  <ul>
309    <li>All transitions are always external. Local transitions are not
310    supported at all. Unfortunately, the UML2.0 specifications are not
311    entirely clear how local transitions are supposed to work, see <a href=
312    "http://thread.gmane.org/gmane.comp.lib.boost.user/18641">here</a> for
313    more information</li>
314
315    <li>There is no direct support for the UML2.0 elements entry point and
316    exit point. However, both can easily be simulated, the former with a
317    typedef and the latter with a state that is a template (with the
318    transition destination as a template parameter)</li>
319  </ul>
320
321  <h2><a name="AssertInStateDestructor" id="AssertInStateDestructor">Why do I
322  get an assert when I access the state machine from a state destructor?</a>
323  </h2>
324
325  <p>When compiled with <code>NDEBUG</code> undefined, running the following
326  program results in a failed assert:</p>
327  <pre>#include &lt;boost/statechart/state_machine.hpp&gt;
328#include &lt;boost/statechart/simple_state.hpp&gt;
329#include &lt;iostream&gt;
330
331struct Initial;
332struct Machine : boost::statechart::state_machine&lt; Machine, Initial &gt;
333{
334  Machine() { someMember_ = 42; }
335  int someMember_;
336};
337
338struct Initial : boost::statechart::simple_state&lt; Initial, Machine &gt;
339{
340  ~Initial() { std::cout &lt;&lt; outermost_context().someMember_; }
341};
342
343int main()
344{
345  Machine().initiate();
346  return 0;
347}</pre>
348  <p>The problem arises because <code>state_machine&lt;&gt;::~state_machine</code>
349  inevitably destructs all remaining active states. At this time,
350  <code>Machine::~Machine</code> has already been run, making it illegal to
351  access any of the <code>Machine</code> members. This problem can be avoided
352  by defining the following destructor:</p>
353  <pre>~Machine() { terminate(); }</pre>
354
355  <h2><a name="EmbeddedApplications" id="EmbeddedApplications">Is
356  Boost.Statechart suitable for embedded applications?</a></h2>
357
358  <p>It depends. As explained under <a href=
359  "performance.html#SpeedVersusScalabilityTradeoffs">Speed versus scalability
360  tradeoffs</a> on the Performance page, the virtually limitless scalability
361  offered by this library does have its price. Especially small and simple
362  FSMs can easily be implemented so that they consume fewer cycles and less
363  memory and occupy less code space in the executable. Here are some
364  obviously <b>very rough</b> estimates:</p>
365
366  <ul>
367    <li>For a state machine with at most one simultaneously active state
368    (that is, the machine is flat and does not have orthogonal regions) with
369    trivial actions, customized memory management and compiled with a good
370    optimizing compiler, a Pentium 4 class CPU should not spend more than
371    1000 cycles inside <code>state_machine&lt;&gt;::process_event()</code>.
372    This worst-case time to process one event scales more or less linearly
373    with the number of simultaneously active states for more complex state
374    machines, with the typical average being much lower than that. So, a
375    fairly complex machine with at most 10 simultaneously active states
376    running on a 100MHz CPU should be able to process more than 10'000 events
377    per second</li>
378
379    <li>A single state machine object uses typically less than 1KB of memory,
380    even if it implements a very complex machine</li>
381
382    <li>For code size, it is difficult to give a concrete guideline but tests
383    with the BitMachine example suggest that code size scales more or less
384    linearly with the number of states (transitions seem to have only little
385    impact). When compiled with MSVC7.1 on Windows, 32 states and 224
386    transitions seem to fit in ~108KB executable code (with all optimizations
387    turned on).<br>
388    Moreover, the library can be compiled with C++ RTTI and exception
389    handling turned off, resulting in significant savings on most
390    platforms</li>
391  </ul>
392
393  <p>As mentioned above, these are very rough estimates derived from the use
394  of the library on a desktop PC, so they should only be used to decide
395  whether there is a point in making your own performance tests on your
396  target platform.</p>
397
398  <h2><a name="HardRealtime" id="HardRealtime">Is your library suitable for
399  applications with hard real-time requirements?</a></h2>
400
401  <p>Yes. Out of the box, the only operations taking potentially
402  non-deterministic time that the library performs are calls to
403  <code>std::allocator&lt;&gt;</code> member functions and
404  <code>dynamic_cast</code>s. <code>std::allocator&lt;&gt;</code> member
405  function calls can be avoided by passing a custom allocator to
406  <code>event&lt;&gt;</code>, <code>state_machine&lt;&gt;</code>,
407  <code>asynchronous_state_machine&lt;&gt;</code>,
408  <code>fifo_scheduler&lt;&gt;</code> and <code>fifo_worker&lt;&gt;</code>.
409  <code>dynamic_cast</code>s can be avoided by not calling the
410  <code>state_cast&lt;&gt;</code> member functions of
411  <code>state_machine&lt;&gt;</code>, <code>simple_state&lt;&gt;</code> and
412  <code>state&lt;&gt;</code> but using the deterministic variant
413  <code>state_downcast&lt;&gt;</code> instead.</p>
414
415  <h2><a name="TemplatedStates" id="TemplatedStates">With templated states I
416  get an error that 'inner_context_type' is not defined. What's
417  wrong?</a></h2>
418
419  <p>The following code generates such an error:</p>
420  <pre>
421#include &lt;boost/statechart/state_machine.hpp&gt;
422#include &lt;boost/statechart/simple_state.hpp&gt;
423
424namespace sc = boost::statechart;
425
426template&lt; typename X &gt; struct A;
427struct Machine : sc::state_machine&lt; Machine, A&lt; int &gt; &gt; {};
428
429template&lt; typename X &gt; struct B;
430template&lt; typename X &gt;
431struct A : sc::simple_state&lt; A&lt; X &gt;, Machine, B&lt; X &gt; &gt; {};
432
433  template&lt; typename X &gt;
434  struct B : sc::simple_state&lt; B&lt; X &gt;, A&lt; X &gt; &gt; {};
435
436int main()
437{
438  Machine machine;
439  machine.initiate();
440  return 0;
441}
442</pre>
443
444  <p>If the templates <code>A</code> and <code>B</code> are replaced with
445  normal types, the above code compiles without errors. This is rooted in the
446  fact that C++ treats forward-declared templates differently than
447  forward-declared types. Namely, the compiler tries to access member
448  typedefs of <code>B&lt; X &gt;</code> at a point where the template has not
449  yet been defined. Luckily, this can easily be avoided by putting all inner
450  initial state arguments in an <code>mpl::list&lt;&gt;</code>, as
451  follows:</p>
452  <pre>
453struct A : sc::simple_state&lt;
454  A&lt; X &gt;, Machine, mpl::list&lt; B&lt; X &gt; &gt; &gt; {};
455</pre>
456
457  <p>See <a href=
458  "http://article.gmane.org/gmane.comp.lib.boost.devel/128741">this post</a>
459  for technical details.</p>
460
461  <h2><a name="CompilerError" id="CompilerError">My compiler reports an error
462  in the library code. Is this a bug in Boost.Statechart?</a></h2>
463
464  <p>Probably not. There are several possible reasons for such compile-time
465  errors:</p>
466
467  <ol>
468    <li>Your compiler is too buggy to compile the library, see <a href=
469    "index.html#SupportedPlatforms">here</a> for information on the status of
470    your compiler. If you absolutely must use such a compiler for your
471    project, I'm afraid Boost.Statechart is not for you.</li>
472
473    <li>The error is reported on a line similar to the following:
474      <pre>
475BOOST_STATIC_ASSERT( ( mpl::less&lt;
476  orthogonal_position,
477  typename context_type::no_of_orthogonal_regions &gt;::value ) );
478</pre>Most probably, there is an error in your code. The library has many
479such compile-time assertions to ensure that invalid state machines cannot be
480compiled (for an idea what kinds of errors are reported at compile time, see
481the compile-fail tests). Above each of these assertions there is a comment
482explaining the problem. On almost all current compilers an error in template
483code is accompanied by the current "instantiation stack". Very much like the
484call stack you see in the debugger, this "instantiation stack" allows you to
485trace the error back through instantiations of library code until you hit the
486line of your code that causes the problem. As an example, here's the MSVC7.1
487error message for the code in InconsistentHistoryTest1.cpp:
488      <pre>
489...\boost\statechart\shallow_history.hpp(34) : error C2027: use of undefined type 'boost::STATIC_ASSERTION_FAILURE&lt;x&gt;'
490  with
491  [
492    x=false
493  ]
494  ...\boost\statechart\shallow_history.hpp(34) : see reference to class template instantiation 'boost::STATIC_ASSERTION_FAILURE&lt;x&gt;' being compiled
495  with
496  [
497    x=false
498  ]
499  ...\boost\statechart\simple_state.hpp(861) : see reference to class template instantiation 'boost::statechart::shallow_history&lt;DefaultState&gt;' being compiled
500  with
501  [
502    DefaultState=B
503  ]
504  ...\boost\statechart\simple_state.hpp(599) : see reference to function template instantiation 'void boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::deep_construct_inner_impl_non_empty::deep_construct_inner_impl&lt;InnerList&gt;(const boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::inner_context_ptr_type &amp;,boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::outermost_context_base_type &amp;)' being compiled
505  with
506  [
507    MostDerived=A,
508    Context=InconsistentHistoryTest,
509    InnerInitial=boost::mpl::list&lt;boost::statechart::shallow_history&lt;B&gt;&gt;,
510    InnerList=boost::statechart::simple_state&lt;A,InconsistentHistoryTest,boost::mpl::list&lt;boost::statechart::shallow_history&lt;B&gt;&gt;&gt;::inner_initial_list
511  ]
512  ...\boost\statechart\simple_state.hpp(567) : see reference to function template instantiation 'void boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::deep_construct_inner&lt;boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::inner_initial_list&gt;(const boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::inner_context_ptr_type &amp;,boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::outermost_context_base_type &amp;)' being compiled
513  with
514  [
515    MostDerived=A,
516    Context=InconsistentHistoryTest,
517    InnerInitial=boost::mpl::list&lt;boost::statechart::shallow_history&lt;B&gt;&gt;
518  ]
519  ...\boost\statechart\simple_state.hpp(563) : while compiling class-template member function 'void boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::deep_construct(const boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::context_ptr_type &amp; ,boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;::outermost_context_base_type &amp;)'
520  with
521  [
522    MostDerived=A,
523    Context=InconsistentHistoryTest,
524    InnerInitial=boost::mpl::list&lt;boost::statechart::shallow_history&lt;B&gt;&gt;
525  ]
526  ...\libs\statechart\test\InconsistentHistoryTest1.cpp(29) : see reference to class template instantiation 'boost::statechart::simple_state&lt;MostDerived,Context,InnerInitial&gt;' being compiled
527  with
528  [
529    MostDerived=A,
530    Context=InconsistentHistoryTest,
531    InnerInitial=boost::mpl::list&lt;boost::statechart::shallow_history&lt;B&gt;&gt;
532  ]
533</pre>Depending on the IDE you use, it is possible that you need to switch to
534another window to see this full error message (e.g. for Visual Studio 2003,
535you need to switch to the Output window). Starting at the top and going down
536the list of instantiations you see that each of them is accompanied by a file
537name and a line number. Ignoring all files belonging to the library, we find
538the culprit close to the bottom in file InconsistentHistoryTest1.cpp on line
53929.
540    </li>
541
542    <li>The error is reported on a line nowhere near a BOOST_STATIC_ASSERT.
543    Use the technique described under point 2 to see what line of your code
544    causes the problem. If your code is correct then you've found a bug in
545    either the compiler or Boost.Statechart. Please <a href=
546    "contact.html">send me</a> a small but complete program showing the
547    problem. Thank you!</li>
548  </ol>
549
550  <h2><a name="DisableHistory" id="DisableHistory">Is it possible to disable
551  history for a state at runtime?</a></h2>
552
553  <p>Yes, see <a href=
554  "reference.html#clear_shallow_history">simple_state::clear_shallow_history()</a>
555  and <a href=
556  "reference.html#clear_deep_history">simple_state::clear_deep_history()</a>.
557  Calling these functions is often preferable to introducting additional
558  normal transitions when ...</p>
559  <ul>
560    <li>a state with history is the target of many transitions,
561    <b>and/or</b></li>
562    <li>the decision to ignore history is made in a different place than
563    the transition to a state with history</li>
564  </ul>
565
566  <h2><a name="Dll" id="Dll">How can I compile a state machine into a dynamic
567  link library (DLL)?</a></h2>
568
569  <p>Invisible to the user, the library uses static data members to implement
570  its own speed-optimized RTTI-mechanism for <code>event&lt;&gt;</code> and
571  <code>simple_state&lt;&gt;</code> subtypes. Whenever such a subtype is
572  defined in a header file and then included in multiple TUs, the linker
573  later needs to eliminate the duplicate definitions of static data members.
574  This usually works flawlessly as long as all these TUs are
575  <b>statically</b> linked into the same binary. It is a lot more complex
576  when DLLs are involved. The TuTest*.?pp files illustrate this:</p>
577
578  <ul>
579    <li><a href="../test/TuTest.hpp">TuTest.hpp</a>: Instantiates a class
580    template containing a static data member</li>
581
582    <li><a href="../test/TuTest.cpp">TuTest.cpp</a>: Includes TuTest.hpp and
583    is compiled into a DLL</li>
584
585    <li><a href="../test/TuTestMain.cpp">TuTestMain.cpp</a>: Includes
586    TuTest.hpp and is compiled into an executable</li>
587  </ul>
588
589  <p>Without any precautions (e.g. <code>__declspec(dllexport)</code> on MSVC
590  compatible compilers), on most platforms both binaries (exe &amp; dll) now
591  contain their own instance of the static data member. Since the RTTI
592  mechanism assumes that there is exactly one object of that member at
593  runtime, the mechanism fails spectacularly when the process running the exe
594  also loads the dll. Different platforms deal differently with this
595  problem:</p>
596
597  <ul>
598    <li>On some platforms (e.g. MinGW) there simply doesn't seem to be a way
599    to enforce that such a member only exists once at runtime. Therefore, the
600    internal RTTI mechanism cannot be used reliably in conjunction with DLLs.
601    Disabling it by defining <a href=
602    "configuration.html#ApplicationDefinedMacros">BOOST_STATECHART_USE_NATIVE_RTTI</a>
603    in all TUs will <b>usually</b> work around the problem</li>
604
605    <li>MSVC-compatible compilers support <code>__declspec(dllimport)</code>
606    and <code>__declspec(dllexport)</code>, which allow to define exactly
607    what needs to be loaded from a DLL (see TuTest for an example how to do
608    this). Therefore, the internal RTTI mechanism can be used but care must
609    be taken to correctly export and import all <code>event&lt;&gt;</code>
610    and <code>simple_state&lt;&gt;</code> subtypes defined in headers that
611    are compiled into more than one binary. Alternatively, of course <a href=
612    "configuration.html#ApplicationDefinedMacros">BOOST_STATECHART_USE_NATIVE_RTTI</a>
613    can also be used to save the work of importing and exporting</li>
614  </ul>
615
616  <h2><a name="PolymorphicEvents" id="PolymorphicEvents">Does
617  Boost.Statechart support polymorphic events?</a></h2>
618
619  <p>No. Although events can be derived from each other to write common code
620  only once, <a href="definitions.html#Reaction">reactions</a> can only be
621  defined for most-derived events.</p>
622
623  <p>Example:</p>
624  <pre>
625template&lt; class MostDerived &gt;
626struct EvButtonPressed : sc::event&lt; MostDerived &gt;
627{
628  // common code
629};
630
631struct EvPlayButtonPressed :
632  EvButtonPressed&lt; EvPlayButtonPressed &gt; {};
633struct EvStopButtonPressed :
634  EvButtonPressed&lt; EvStopButtonPressed &gt; {};
635struct EvForwardButtonPressed :
636  EvButtonPressed&lt; EvForwardButtonPressed &gt; {};
637
638/* ... */
639
640// We want to turn the player on, no matter what button we
641// press in the Off state. Although we can write the reaction
642// code only once, we must mention all most-derived events in
643// the reaction list.
644struct Off : sc::simple_state&lt; Off, Mp3Player &gt;
645{
646  typedef mpl::list&lt;
647    sc::custom_reaction&lt; EvPlayButtonPressed &gt;,
648    sc::custom_reaction&lt; EvStopButtonPressed &gt;,
649    sc::custom_reaction&lt; EvForwardButtonPressed &gt;
650  &gt; reactions;
651
652  template&lt; class MostDerived &gt;
653  sc::result react( const EvButtonPressed&lt; MostDerived &gt; &amp; )
654  {
655    // ...
656  }
657};
658</pre>
659
660  <h2><a name="WrongExitActionOrder" id="WrongExitActionOrder">Why are
661  exit-actions called in the wrong order when I use multiple
662  inheritance?</a></h2>
663
664  <p><b>Update</b>: The implementation has changed considerably in this area.
665  It is still possible to get this behavior under rare circumstances (when an
666  action propagates an exception in a state machine with orthogonal regions
667  <b>and</b> if the statechart layout satisfies certain conditions), but it
668  can no longer be demonstrated with the example program below. However, the
669  described workaround is still valid and ensures that this behavior will
670  never show up.</p>
671
672  <p>They definitely aren't for the <code>simple_state&lt;&gt;</code> and
673  <code>state&lt;&gt;</code> subtypes, but the destructors of additional
674  bases might be called in construction order (rather than the reverse
675  construction order):</p>
676  <pre>
677#include &lt;boost/statechart/state_machine.hpp&gt;
678#include &lt;boost/statechart/simple_state.hpp&gt;
679
680namespace sc = boost::statechart;
681
682class EntryExitDisplayer
683{
684  protected:
685    EntryExitDisplayer( const char * pName ) :
686      pName_( pName )
687    {
688      std::cout &lt;&lt; pName_ &lt;&lt; " entered\n";
689    }
690
691    ~EntryExitDisplayer()
692    {
693      std::cout &lt;&lt; pName_ &lt;&lt; " exited\n";
694    }
695
696  private:
697    const char * const pName_;
698};
699
700struct Outer;
701struct Machine : sc::state_machine&lt; Machine, Outer &gt; {};
702struct Inner;
703struct Outer : EntryExitDisplayer, sc::simple_state&lt;
704  Outer, Machine, Inner &gt;
705{
706  Outer() : EntryExitDisplayer( "Outer" ) {}
707};
708
709struct Inner : EntryExitDisplayer,
710  sc::simple_state&lt; Inner, Outer &gt;
711{
712  Inner() : EntryExitDisplayer( "Inner" ) {}
713};
714
715int main()
716{
717  Machine myMachine;
718  myMachine.initiate();
719  return 0;
720}
721</pre>
722
723  <p>This program will produce the following output:</p>
724  <pre>
725Outer entered
726Inner entered
727Outer exited
728Inner exited
729</pre>
730
731  <p>That is, the <b><code>EntryExitDisplayer</code> base class portion</b>
732  of <code>Outer</code> is destructed before the one of <code>Inner</code>
733  although <code>Inner::~Inner()</code> is called before
734  <code>Outer::~Outer()</code>. This somewhat counter-intuitive behavior is
735  caused by the following facts:</p>
736
737  <ul>
738    <li>The <code>simple_state&lt;&gt;</code> base class portion of
739    <code>Inner</code> is responsible to destruct <code>Outer</code></li>
740
741    <li>Destructors of base class portions are called in the reverse order of
742    construction</li>
743  </ul>
744
745  <p>So, when the <code>Outer</code> destructor is called the call stack
746  looks as follows:</p>
747  <pre>
748Outer::~Outer()
749simple_state&lt; Inner, ... &gt;::~simple_state()
750Inner::~Inner()
751</pre>
752
753  <p>Note that <code>Inner::~Inner()</code> did not yet have a chance to
754  destroy its <code>EntryExitDisplayer</code> base class portion, as it first
755  has to call the destructor of the <b>second</b> base class. Now
756  <code>Outer::~Outer()</code> will first destruct its <code>simple_state&lt;
757  Outer, ... &gt;</code> base class portion and then do the same with its
758  <code>EntryExitDisplayer</code> base class portion. The stack then unwinds
759  back to <code>Inner::~Inner()</code>, which can then finally finish by
760  calling <code>EntryExitDisplayer::~EntryExitDisplayer()</code>.</p>
761
762  <p>Luckily, there is an easy work-around: Always let
763  <code>simple_state&lt;&gt;</code> and <code>state&lt;&gt;</code> be the
764  first base class of a state. This ensures that destructors of additional
765  bases are called before recursion employed by state base destructors can
766  alter the order of destruction.</p>
767  <hr>
768
769  <p><a href="http://validator.w3.org/check?uri=referer"><img border="0" src=
770  "../../../doc/images/valid-html401.png" alt="Valid HTML 4.01 Transitional"
771  height="31" width="88"></a></p>
772
773  <p>Revised 05 January, 2008</p>
774
775  <p><i>Copyright &copy; 2003-2008 <a href="contact.html">Andreas Huber
776  D&ouml;nni</a></i></p>
777
778  <p><i>Distributed under the Boost Software License, Version 1.0. (See
779  accompanying file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or
780  copy at <a href=
781  "http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</i></p>
782</body>
783</html>
784