Blame libs/statechart/doc/faq.html

Packit 58578d
Packit 58578d
Packit 58578d
<html>
Packit 58578d
<head>
Packit 58578d
  <meta http-equiv="Content-Language" content="en-us">
Packit 58578d
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
Packit 58578d
  <meta name="GENERATOR" content="Microsoft FrontPage 6.0">
Packit 58578d
  <meta name="ProgId" content="FrontPage.Editor.Document">
Packit 58578d
  <link rel="stylesheet" type="text/css" href="../../../boost.css">
Packit 58578d
Packit 58578d
  <title>The Boost Statechart Library - FAQ</title>
Packit 58578d
</head>
Packit 58578d
Packit 58578d
<body link="#0000FF" vlink="#800080">
Packit 58578d
  
Packit 58578d
  "header">
Packit 58578d
    
Packit 58578d
      
Packit 58578d
        

Packit 58578d
        "../../../boost.png" border="0" width="277" height="86">
Packit 58578d
      
Packit 58578d
Packit 58578d
      
Packit 58578d
        

The Boost Statechart Library

Packit 58578d
Packit 58578d
        

Frequently Asked Questions (FAQs)

Packit 58578d
      
Packit 58578d
    
Packit 58578d
  
Packit 58578d
  
Packit 58578d
Packit 58578d
  
Packit 58578d
    
What's so cool about state-local
Packit 58578d
    storage?
Packit 58578d
Packit 58578d
    
How can I hide the inner workings of a
Packit 58578d
    state machine from its clients?
Packit 58578d
Packit 58578d
    
Is it possible to inherit from a given
Packit 58578d
    state machine and modify its layout in the subclass?
Packit 58578d
Packit 58578d
    
What about UML2.0 features?
Packit 58578d
    
Packit 58578d
    
Why do I get an assert when I
Packit 58578d
    access the state machine from a state destructor?
Packit 58578d
Packit 58578d
    
Is Boost.Statechart suitable for
Packit 58578d
    embedded applications?
Packit 58578d
Packit 58578d
    
Is your library suitable for applications
Packit 58578d
    with hard real-time requirements?
Packit 58578d
Packit 58578d
    
With templated states I get an error that
Packit 58578d
    'inner_context_type' is not defined. What's wrong?
Packit 58578d
Packit 58578d
    
My compiler reports an error in the library
Packit 58578d
    code. Is this a bug in Boost.Statechart?
Packit 58578d
Packit 58578d
    
Is it possible to disable history for a
Packit 58578d
    state at runtime?
Packit 58578d
Packit 58578d
    
How can I compile a state machine into a dynamic link
Packit 58578d
    library (DLL)?
Packit 58578d
Packit 58578d
    
Does Boost.Statechart support
Packit 58578d
    polymorphic events?
Packit 58578d
Packit 58578d
    
Why are exit-actions called in the
Packit 58578d
    wrong order when I use multiple inheritance?
Packit 58578d
  
Packit 58578d
Packit 58578d
  

What's so cool about

Packit 58578d
  state-local storage?
Packit 58578d
Packit 58578d
  

This is best explained with an example:

Packit 58578d
  
Packit 58578d
struct Active;
Packit 58578d
struct Stopped;
Packit 58578d
struct Running;
Packit 58578d
struct StopWatch : sc::state_machine< StopWatch, Active >
Packit 58578d
{
Packit 58578d
  // startTime_ remains uninitialized, because there is no reasonable default
Packit 58578d
  StopWatch() : elapsedTime_( 0.0 ) {}
Packit 58578d
  ~StopWatch()
Packit 58578d
  {
Packit 58578d
    terminate();
Packit 58578d
  }
Packit 58578d
Packit 58578d
  double ElapsedTime() const
Packit 58578d
  {
Packit 58578d
    // Ugly switch over the current state.
Packit 58578d
    if ( state_cast< const Stopped * >() != 0 )
Packit 58578d
    {
Packit 58578d
      return elapsedTime_;
Packit 58578d
    }
Packit 58578d
    else if ( state_cast< const Running * >() != 0 )
Packit 58578d
    {
Packit 58578d
      return elapsedTime_ + std::difftime( std::time( 0 ), startTime_ );
Packit 58578d
    }
Packit 58578d
    else // we're terminated
Packit 58578d
    {
Packit 58578d
      throw std::bad_cast();
Packit 58578d
    }
Packit 58578d
  }
Packit 58578d
Packit 58578d
  // elapsedTime_ is only meaningful when the machine is not terminated
Packit 58578d
  double elapsedTime_;
Packit 58578d
  // startTime_ is only meaningful when the machine is in Running
Packit 58578d
  std::time_t startTime_;
Packit 58578d
};
Packit 58578d
Packit 58578d
struct Active : sc::state< Active, StopWatch, Stopped >
Packit 58578d
{
Packit 58578d
  typedef sc::transition< EvReset, Active > reactions;
Packit 58578d
Packit 58578d
  Active( my_context ctx ) : my_base( ctx )
Packit 58578d
  {
Packit 58578d
    outermost_context().elapsedTime_ = 0.0;
Packit 58578d
  }
Packit 58578d
};
Packit 58578d
Packit 58578d
  struct Running : sc::state< Running, Active >
Packit 58578d
  {
Packit 58578d
    typedef sc::transition< EvStartStop, Stopped > reactions;
Packit 58578d
Packit 58578d
    Running( my_context ctx ) : my_base( ctx )
Packit 58578d
    {
Packit 58578d
      outermost_context().startTime_ = std::time( 0 );
Packit 58578d
    }
Packit 58578d
Packit 58578d
    ~Running()
Packit 58578d
    {
Packit 58578d
      outermost_context().elapsedTime_ +=
Packit 58578d
        std::difftime( std::time( 0 ), outermost_context().startTime_ );
Packit 58578d
    }
Packit 58578d
  };
Packit 58578d
Packit 58578d
  struct Stopped : sc::simple_state< Stopped, Active >
Packit 58578d
  {
Packit 58578d
    typedef sc::transition< EvStartStop, Running > reactions;
Packit 58578d
  };
Packit 58578d
Packit 58578d
Packit 58578d
  

This StopWatch does not make any use of state-local storage while

Packit 58578d
  implementing the same behavior as the 
Packit 58578d
  "tutorial.html#BasicTopicsAStopWatch">tutorial StopWatch. Even though
Packit 58578d
  this code is probably easier to read for the untrained eye, it does have a
Packit 58578d
  few problems that are absent in the original:

Packit 58578d
Packit 58578d
  
    Packit 58578d
        
  • This StopWatch class has data members that have a meaningful value
  • Packit 58578d
        only if the state machine happens to be in a certain state. That is, the
    Packit 58578d
        lifetimes of these variables are not identical with the one of the
    Packit 58578d
        StopWatch object containing them. Since the lifetimes are managed by the
    Packit 58578d
        entry and exit actions of states, we need to use an ugly switch over the
    Packit 58578d
        current state (see StopWatch::ElapsedTime()) if we want to
    Packit 58578d
        access them from a context where the current state is unclear. This
    Packit 58578d
        essentially duplicates some of the state logic of the FSM. Therefore,
    Packit 58578d
        whenever we need to change the layout of the state machine we will likely
    Packit 58578d
        also need to change the ugly switch. Even worse, if we forget to change
    Packit 58578d
        the switch, the code will probably still compile and maybe even silently
    Packit 58578d
        do the wrong thing. Note that this is impossible with the version in the
    Packit 58578d
        tutorial, which will at least throw an exception and often just refuse to
    Packit 58578d
        compile. Moreover, for the tutorial StopWatch there's a much higher
    Packit 58578d
        chance that a programmer will get a change correct the first time since
    Packit 58578d
        the code that calculates the elapsed time is located close to the code
    Packit 58578d
        that updates the variables
    Packit 58578d
    Packit 58578d
        
  • We need to change the StopWatch class whenever we want to introduce a
  • Packit 58578d
        new variable or change the type of an already existing variable. That is,
    Packit 58578d
        many changes in the FSM will likely lead to a change in the StopWatch
    Packit 58578d
        class. In all FSMs that do not employ state-local storage, the
    Packit 58578d
        state_machine<> subtype will therefore be a change
    Packit 58578d
        hotspot, which is a pretty sure indicator for a bad design
    Packit 58578d
      
    Packit 58578d
    Packit 58578d
      

    Both points are not much of a problem in a small example like this,

    Packit 58578d
      which can easily be implemented in a single translation unit by a single
    Packit 58578d
      programmer. However, they quickly become a major problem for a big complex
    Packit 58578d
      machine spread over multiple translation units, which are possibly even
    Packit 58578d
      maintained by different programmers.

    Packit 58578d
    Packit 58578d
      

    How can I hide the

    Packit 58578d
      inner workings of a state machine from its clients?
    Packit 58578d
    Packit 58578d
      

    To see why and how this is possible it is important to recall the

    Packit 58578d
      following facts:

    Packit 58578d
    Packit 58578d
      
      Packit 58578d
          
    • Member functions of a C++ class template are instantiated at the
    • Packit 58578d
          point where they're actually called. If the function is never called, it
      Packit 58578d
          will not be instantiated and not a single assembly instruction will ever
      Packit 58578d
          be generated
      Packit 58578d
      Packit 58578d
          
    • The InitialState template parameter of
    • Packit 58578d
          sc::state_machine can be an incomplete type (i.e. forward
      Packit 58578d
          declared)
      Packit 58578d
        
      Packit 58578d
      Packit 58578d
        

      The class template member function

      Packit 58578d
        state_machine<>::initiate() creates an object of the
      Packit 58578d
        initial state. So, the definition of this state must be known before the
      Packit 58578d
        compiler reaches the point where initiate() is called. To be
      Packit 58578d
        able to hide the initial state of a state machine in a .cpp file we must
      Packit 58578d
        therefore no longer let clients call initiate(). Instead, we
      Packit 58578d
        do so in the .cpp file, at a point where the full definition of the initial
      Packit 58578d
        state is known.

      Packit 58578d
      Packit 58578d
        

      Example:

      Packit 58578d
      Packit 58578d
        

      StopWatch.hpp:

      Packit 58578d
        
      Packit 58578d
      // define events ...
      Packit 58578d
      Packit 58578d
      struct Active; // the only visible forward
      Packit 58578d
      struct StopWatch : sc::state_machine< StopWatch, Active >
      Packit 58578d
      {
      Packit 58578d
        StopWatch();
      Packit 58578d
      };
      Packit 58578d
      Packit 58578d
      Packit 58578d
        

      StopWatch.cpp:

      Packit 58578d
        
      Packit 58578d
      struct Stopped;
      Packit 58578d
      struct Active : sc::simple_state< Active, StopWatch, Stopped >
      Packit 58578d
      {
      Packit 58578d
        typedef sc::transition< EvReset, Active > reactions;
      Packit 58578d
      };
      Packit 58578d
      Packit 58578d
        struct Running : sc::simple_state< Running, Active >
      Packit 58578d
        {
      Packit 58578d
          typedef sc::transition< EvStartStop, Stopped > reactions;
      Packit 58578d
        };
      Packit 58578d
      Packit 58578d
        struct Stopped : sc::simple_state< Stopped, Active >
      Packit 58578d
        {
      Packit 58578d
          typedef sc::transition< EvStartStop, Running > reactions;
      Packit 58578d
        };
      Packit 58578d
      Packit 58578d
      StopWatch::StopWatch()
      Packit 58578d
      {
      Packit 58578d
        // For example, we might want to ensure that the state
      Packit 58578d
        // machine is already started after construction.
      Packit 58578d
        // Alternatively, we could add our own initiate() function
      Packit 58578d
        // to StopWatch and call the base class initiate() in the
      Packit 58578d
        // implementation.
      Packit 58578d
        initiate();
      Packit 58578d
      }
      Packit 58578d
      Packit 58578d
        

      The PingPong example demonstrates how the inner workings of an

      Packit 58578d
        asynchronous_state_machine<> subclass can be hidden.

      Packit 58578d
      Packit 58578d
        

      Is it possible to

      Packit 58578d
        inherit from a given state machine and modify its layout in the
      Packit 58578d
        subclass?
      Packit 58578d
      Packit 58578d
        

      Yes, but contrary to what some FSM code generators allow,

      Packit 58578d
        Boost.Statechart machines can do so only in a way that was foreseen by the
      Packit 58578d
        designer of the base state machine:

      Packit 58578d
        
      Packit 58578d
      struct EvStart : sc::event< EvStart > {};
      Packit 58578d
      Packit 58578d
      struct Idle;
      Packit 58578d
      struct PumpBase : sc::state_machine< PumpBase, Idle >
      Packit 58578d
      {
      Packit 58578d
        virtual sc::result react(
      Packit 58578d
          Idle & idle, const EvStart & ) const;
      Packit 58578d
      };
      Packit 58578d
      Packit 58578d
      struct Idle : sc::simple_state< Idle, PumpBase >
      Packit 58578d
      {
      Packit 58578d
        typedef sc::custom_reaction< EvStart > reactions;
      Packit 58578d
      Packit 58578d
        sc::result react( const EvStart & evt )
      Packit 58578d
        {
      Packit 58578d
          return context< PumpBase >().react( *this, evt );
      Packit 58578d
        }
      Packit 58578d
      };
      Packit 58578d
      Packit 58578d
      struct Running : sc::simple_state< Running, PumpBase > {};
      Packit 58578d
      Packit 58578d
      sc::result PumpBase::react(
      Packit 58578d
        Idle & idle, const EvStart & ) const
      Packit 58578d
      {
      Packit 58578d
        return idle.transit< Running >();
      Packit 58578d
      }
      Packit 58578d
      Packit 58578d
      Packit 58578d
      struct MyRunning : sc::simple_state< MyRunning, PumpBase > {};
      Packit 58578d
      Packit 58578d
      struct MyPump : PumpBase
      Packit 58578d
      {
      Packit 58578d
        virtual sc::result react(
      Packit 58578d
          Idle & idle, const EvStart & ) const
      Packit 58578d
        {
      Packit 58578d
          return idle.transit< MyRunning >();
      Packit 58578d
        }
      Packit 58578d
      };
      Packit 58578d
      Packit 58578d
      Packit 58578d
        

      What about UML 2.0 features?

      Packit 58578d
      Packit 58578d
        

      The library was designed before 2.0 came along. Therefore, if not

      Packit 58578d
        explicitly noted otherwise, the library implements the behavior mandated by
      Packit 58578d
        the UML1.5 standard. Here's an incomplete list of differences between the
      Packit 58578d
        2.0 semantics & Boost.Statechart semantics:

      Packit 58578d
      Packit 58578d
        
        Packit 58578d
            
      • All transitions are always external. Local transitions are not
      • Packit 58578d
            supported at all. Unfortunately, the UML2.0 specifications are not
        Packit 58578d
            entirely clear how local transitions are supposed to work, see 
        Packit 58578d
            "http://thread.gmane.org/gmane.comp.lib.boost.user/18641">here for
        Packit 58578d
            more information
        Packit 58578d
        Packit 58578d
            
      • There is no direct support for the UML2.0 elements entry point and
      • Packit 58578d
            exit point. However, both can easily be simulated, the former with a
        Packit 58578d
            typedef and the latter with a state that is a template (with the
        Packit 58578d
            transition destination as a template parameter)
        Packit 58578d
          
        Packit 58578d
        Packit 58578d
          

        Why do I

        Packit 58578d
          get an assert when I access the state machine from a state destructor?
        Packit 58578d
          
        Packit 58578d
        Packit 58578d
          

        When compiled with NDEBUG undefined, running the following

        Packit 58578d
          program results in a failed assert:

        Packit 58578d
          
        #include <boost/statechart/state_machine.hpp>
        Packit 58578d
        #include <boost/statechart/simple_state.hpp>
        Packit 58578d
        #include <iostream>
        Packit 58578d
        Packit 58578d
        struct Initial;
        Packit 58578d
        struct Machine : boost::statechart::state_machine< Machine, Initial >
        Packit 58578d
        {
        Packit 58578d
          Machine() { someMember_ = 42; }
        Packit 58578d
          int someMember_;
        Packit 58578d
        };
        Packit 58578d
        Packit 58578d
        struct Initial : boost::statechart::simple_state< Initial, Machine >
        Packit 58578d
        {
        Packit 58578d
          ~Initial() { std::cout << outermost_context().someMember_; }
        Packit 58578d
        };
        Packit 58578d
        Packit 58578d
        int main()
        Packit 58578d
        {
        Packit 58578d
          Machine().initiate();
        Packit 58578d
          return 0;
        Packit 58578d
        }
        Packit 58578d
          

        The problem arises because state_machine<>::~state_machine

        Packit 58578d
          inevitably destructs all remaining active states. At this time,
        Packit 58578d
          Machine::~Machine has already been run, making it illegal to
        Packit 58578d
          access any of the Machine members. This problem can be avoided
        Packit 58578d
          by defining the following destructor:

        Packit 58578d
          
        ~Machine() { terminate(); }
        Packit 58578d
        Packit 58578d
          

        Is

        Packit 58578d
          Boost.Statechart suitable for embedded applications?
        Packit 58578d
        Packit 58578d
          

        It depends. As explained under

        Packit 58578d
          "performance.html#SpeedVersusScalabilityTradeoffs">Speed versus scalability
        Packit 58578d
          tradeoffs on the Performance page, the virtually limitless scalability
        Packit 58578d
          offered by this library does have its price. Especially small and simple
        Packit 58578d
          FSMs can easily be implemented so that they consume fewer cycles and less
        Packit 58578d
          memory and occupy less code space in the executable. Here are some
        Packit 58578d
          obviously very rough estimates:

        Packit 58578d
        Packit 58578d
          
          Packit 58578d
              
        • For a state machine with at most one simultaneously active state
        • Packit 58578d
              (that is, the machine is flat and does not have orthogonal regions) with
          Packit 58578d
              trivial actions, customized memory management and compiled with a good
          Packit 58578d
              optimizing compiler, a Pentium 4 class CPU should not spend more than
          Packit 58578d
              1000 cycles inside state_machine<>::process_event().
          Packit 58578d
              This worst-case time to process one event scales more or less linearly
          Packit 58578d
              with the number of simultaneously active states for more complex state
          Packit 58578d
              machines, with the typical average being much lower than that. So, a
          Packit 58578d
              fairly complex machine with at most 10 simultaneously active states
          Packit 58578d
              running on a 100MHz CPU should be able to process more than 10'000 events
          Packit 58578d
              per second
          Packit 58578d
          Packit 58578d
              
        • A single state machine object uses typically less than 1KB of memory,
        • Packit 58578d
              even if it implements a very complex machine
          Packit 58578d
          Packit 58578d
              
        • For code size, it is difficult to give a concrete guideline but tests
        • Packit 58578d
              with the BitMachine example suggest that code size scales more or less
          Packit 58578d
              linearly with the number of states (transitions seem to have only little
          Packit 58578d
              impact). When compiled with MSVC7.1 on Windows, 32 states and 224
          Packit 58578d
              transitions seem to fit in ~108KB executable code (with all optimizations
          Packit 58578d
              turned on).
          Packit 58578d
              Moreover, the library can be compiled with C++ RTTI and exception
          Packit 58578d
              handling turned off, resulting in significant savings on most
          Packit 58578d
              platforms
          Packit 58578d
            
          Packit 58578d
          Packit 58578d
            

          As mentioned above, these are very rough estimates derived from the use

          Packit 58578d
            of the library on a desktop PC, so they should only be used to decide
          Packit 58578d
            whether there is a point in making your own performance tests on your
          Packit 58578d
            target platform.

          Packit 58578d
          Packit 58578d
            

          Is your library suitable for

          Packit 58578d
            applications with hard real-time requirements?
          Packit 58578d
          Packit 58578d
            

          Yes. Out of the box, the only operations taking potentially

          Packit 58578d
            non-deterministic time that the library performs are calls to
          Packit 58578d
            std::allocator<> member functions and
          Packit 58578d
            dynamic_casts. std::allocator<> member
          Packit 58578d
            function calls can be avoided by passing a custom allocator to
          Packit 58578d
            event<>, state_machine<>,
          Packit 58578d
            asynchronous_state_machine<>,
          Packit 58578d
            fifo_scheduler<> and fifo_worker<>.
          Packit 58578d
            dynamic_casts can be avoided by not calling the
          Packit 58578d
            state_cast<> member functions of
          Packit 58578d
            state_machine<>, simple_state<> and
          Packit 58578d
            state<> but using the deterministic variant
          Packit 58578d
            state_downcast<> instead.

          Packit 58578d
          Packit 58578d
            

          With templated states I

          Packit 58578d
            get an error that 'inner_context_type' is not defined. What's
          Packit 58578d
            wrong?
          Packit 58578d
          Packit 58578d
            

          The following code generates such an error:

          Packit 58578d
            
          Packit 58578d
          #include <boost/statechart/state_machine.hpp>
          Packit 58578d
          #include <boost/statechart/simple_state.hpp>
          Packit 58578d
          Packit 58578d
          namespace sc = boost::statechart;
          Packit 58578d
          Packit 58578d
          template< typename X > struct A;
          Packit 58578d
          struct Machine : sc::state_machine< Machine, A< int > > {};
          Packit 58578d
          Packit 58578d
          template< typename X > struct B;
          Packit 58578d
          template< typename X >
          Packit 58578d
          struct A : sc::simple_state< A< X >, Machine, B< X > > {};
          Packit 58578d
          Packit 58578d
            template< typename X >
          Packit 58578d
            struct B : sc::simple_state< B< X >, A< X > > {};
          Packit 58578d
          Packit 58578d
          int main()
          Packit 58578d
          {
          Packit 58578d
            Machine machine;
          Packit 58578d
            machine.initiate();
          Packit 58578d
            return 0;
          Packit 58578d
          }
          Packit 58578d
          Packit 58578d
          Packit 58578d
            

          If the templates A and B are replaced with

          Packit 58578d
            normal types, the above code compiles without errors. This is rooted in the
          Packit 58578d
            fact that C++ treats forward-declared templates differently than
          Packit 58578d
            forward-declared types. Namely, the compiler tries to access member
          Packit 58578d
            typedefs of B< X > at a point where the template has not
          Packit 58578d
            yet been defined. Luckily, this can easily be avoided by putting all inner
          Packit 58578d
            initial state arguments in an mpl::list<>, as
          Packit 58578d
            follows:

          Packit 58578d
            
          Packit 58578d
          struct A : sc::simple_state<
          Packit 58578d
            A< X >, Machine, mpl::list< B< X > > > {};
          Packit 58578d
          Packit 58578d
          Packit 58578d
            

          See

          Packit 58578d
            "http://article.gmane.org/gmane.comp.lib.boost.devel/128741">this post
          Packit 58578d
            for technical details.

          Packit 58578d
          Packit 58578d
            

          My compiler reports an error

          Packit 58578d
            in the library code. Is this a bug in Boost.Statechart?
          Packit 58578d
          Packit 58578d
            

          Probably not. There are several possible reasons for such compile-time

          Packit 58578d
            errors:

          Packit 58578d
          Packit 58578d
            
            Packit 58578d
                
          1. Your compiler is too buggy to compile the library, see
          2. Packit 58578d
                "index.html#SupportedPlatforms">here for information on the status of
            Packit 58578d
                your compiler. If you absolutely must use such a compiler for your
            Packit 58578d
                project, I'm afraid Boost.Statechart is not for you.
            Packit 58578d
            Packit 58578d
                
          3. The error is reported on a line similar to the following:
          4. Packit 58578d
                  
            Packit 58578d
            BOOST_STATIC_ASSERT( ( mpl::less<
            Packit 58578d
              orthogonal_position,
            Packit 58578d
              typename context_type::no_of_orthogonal_regions >::value ) );
            Packit 58578d
            Most probably, there is an error in your code. The library has many
            Packit 58578d
            such compile-time assertions to ensure that invalid state machines cannot be
            Packit 58578d
            compiled (for an idea what kinds of errors are reported at compile time, see
            Packit 58578d
            the compile-fail tests). Above each of these assertions there is a comment
            Packit 58578d
            explaining the problem. On almost all current compilers an error in template
            Packit 58578d
            code is accompanied by the current "instantiation stack". Very much like the
            Packit 58578d
            call stack you see in the debugger, this "instantiation stack" allows you to
            Packit 58578d
            trace the error back through instantiations of library code until you hit the
            Packit 58578d
            line of your code that causes the problem. As an example, here's the MSVC7.1
            Packit 58578d
            error message for the code in InconsistentHistoryTest1.cpp:
            Packit 58578d
                  
            Packit 58578d
            ...\boost\statechart\shallow_history.hpp(34) : error C2027: use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'
            Packit 58578d
              with
            Packit 58578d
              [
            Packit 58578d
                x=false
            Packit 58578d
              ]
            Packit 58578d
              ...\boost\statechart\shallow_history.hpp(34) : see reference to class template instantiation 'boost::STATIC_ASSERTION_FAILURE<x>' being compiled
            Packit 58578d
              with
            Packit 58578d
              [
            Packit 58578d
                x=false
            Packit 58578d
              ]
            Packit 58578d
              ...\boost\statechart\simple_state.hpp(861) : see reference to class template instantiation 'boost::statechart::shallow_history<DefaultState>' being compiled
            Packit 58578d
              with
            Packit 58578d
              [
            Packit 58578d
                DefaultState=B
            Packit 58578d
              ]
            Packit 58578d
              ...\boost\statechart\simple_state.hpp(599) : see reference to function template instantiation 'void boost::statechart::simple_state<MostDerived,Context,InnerInitial>::deep_construct_inner_impl_non_empty::deep_construct_inner_impl<InnerList>(const boost::statechart::simple_state<MostDerived,Context,InnerInitial>::inner_context_ptr_type &,boost::statechart::simple_state<MostDerived,Context,InnerInitial>::outermost_context_base_type &)' being compiled
            Packit 58578d
              with
            Packit 58578d
              [
            Packit 58578d
                MostDerived=A,
            Packit 58578d
                Context=InconsistentHistoryTest,
            Packit 58578d
                InnerInitial=boost::mpl::list<boost::statechart::shallow_history<B>>,
            Packit 58578d
                InnerList=boost::statechart::simple_state<A,InconsistentHistoryTest,boost::mpl::list<boost::statechart::shallow_history<B>>>::inner_initial_list
            Packit 58578d
              ]
            Packit 58578d
              ...\boost\statechart\simple_state.hpp(567) : see reference to function template instantiation 'void boost::statechart::simple_state<MostDerived,Context,InnerInitial>::deep_construct_inner<boost::statechart::simple_state<MostDerived,Context,InnerInitial>::inner_initial_list>(const boost::statechart::simple_state<MostDerived,Context,InnerInitial>::inner_context_ptr_type &,boost::statechart::simple_state<MostDerived,Context,InnerInitial>::outermost_context_base_type &)' being compiled
            Packit 58578d
              with
            Packit 58578d
              [
            Packit 58578d
                MostDerived=A,
            Packit 58578d
                Context=InconsistentHistoryTest,
            Packit 58578d
                InnerInitial=boost::mpl::list<boost::statechart::shallow_history<B>>
            Packit 58578d
              ]
            Packit 58578d
              ...\boost\statechart\simple_state.hpp(563) : while compiling class-template member function 'void boost::statechart::simple_state<MostDerived,Context,InnerInitial>::deep_construct(const boost::statechart::simple_state<MostDerived,Context,InnerInitial>::context_ptr_type & ,boost::statechart::simple_state<MostDerived,Context,InnerInitial>::outermost_context_base_type &)'
            Packit 58578d
              with
            Packit 58578d
              [
            Packit 58578d
                MostDerived=A,
            Packit 58578d
                Context=InconsistentHistoryTest,
            Packit 58578d
                InnerInitial=boost::mpl::list<boost::statechart::shallow_history<B>>
            Packit 58578d
              ]
            Packit 58578d
              ...\libs\statechart\test\InconsistentHistoryTest1.cpp(29) : see reference to class template instantiation 'boost::statechart::simple_state<MostDerived,Context,InnerInitial>' being compiled
            Packit 58578d
              with
            Packit 58578d
              [
            Packit 58578d
                MostDerived=A,
            Packit 58578d
                Context=InconsistentHistoryTest,
            Packit 58578d
                InnerInitial=boost::mpl::list<boost::statechart::shallow_history<B>>
            Packit 58578d
              ]
            Packit 58578d
            Depending on the IDE you use, it is possible that you need to switch to
            Packit 58578d
            another window to see this full error message (e.g. for Visual Studio 2003,
            Packit 58578d
            you need to switch to the Output window). Starting at the top and going down
            Packit 58578d
            the list of instantiations you see that each of them is accompanied by a file
            Packit 58578d
            name and a line number. Ignoring all files belonging to the library, we find
            Packit 58578d
            the culprit close to the bottom in file InconsistentHistoryTest1.cpp on line
            Packit 58578d
            29.
            Packit 58578d
                
            Packit 58578d
            Packit 58578d
                
          5. The error is reported on a line nowhere near a BOOST_STATIC_ASSERT.
          6. Packit 58578d
                Use the technique described under point 2 to see what line of your code
            Packit 58578d
                causes the problem. If your code is correct then you've found a bug in
            Packit 58578d
                either the compiler or Boost.Statechart. Please 
            Packit 58578d
                "contact.html">send me a small but complete program showing the
            Packit 58578d
                problem. Thank you!
            Packit 58578d
              
            Packit 58578d
            Packit 58578d
              

            Is it possible to disable

            Packit 58578d
              history for a state at runtime?
            Packit 58578d
            Packit 58578d
              

            Yes, see

            Packit 58578d
              "reference.html#clear_shallow_history">simple_state::clear_shallow_history()
            Packit 58578d
              and 
            Packit 58578d
              "reference.html#clear_deep_history">simple_state::clear_deep_history().
            Packit 58578d
              Calling these functions is often preferable to introducting additional
            Packit 58578d
              normal transitions when ...

            Packit 58578d
              
              Packit 58578d
                  
            • a state with history is the target of many transitions,
            • Packit 58578d
                  and/or
              Packit 58578d
                  
            • the decision to ignore history is made in a different place than
            • Packit 58578d
                  the transition to a state with history
              Packit 58578d
                
              Packit 58578d
              Packit 58578d
                

              How can I compile a state machine into a dynamic

              Packit 58578d
                link library (DLL)?
              Packit 58578d
              Packit 58578d
                

              Invisible to the user, the library uses static data members to implement

              Packit 58578d
                its own speed-optimized RTTI-mechanism for event<> and
              Packit 58578d
                simple_state<> subtypes. Whenever such a subtype is
              Packit 58578d
                defined in a header file and then included in multiple TUs, the linker
              Packit 58578d
                later needs to eliminate the duplicate definitions of static data members.
              Packit 58578d
                This usually works flawlessly as long as all these TUs are
              Packit 58578d
                statically linked into the same binary. It is a lot more complex
              Packit 58578d
                when DLLs are involved. The TuTest*.?pp files illustrate this:

              Packit 58578d
              Packit 58578d
                
                Packit 58578d
                    
              • TuTest.hpp: Instantiates a class
              • Packit 58578d
                    template containing a static data member
                Packit 58578d
                Packit 58578d
                    
              • TuTest.cpp: Includes TuTest.hpp and
              • Packit 58578d
                    is compiled into a DLL
                Packit 58578d
                Packit 58578d
                    
              • TuTestMain.cpp: Includes
              • Packit 58578d
                    TuTest.hpp and is compiled into an executable
                Packit 58578d
                  
                Packit 58578d
                Packit 58578d
                  

                Without any precautions (e.g. __declspec(dllexport) on MSVC

                Packit 58578d
                  compatible compilers), on most platforms both binaries (exe & dll) now
                Packit 58578d
                  contain their own instance of the static data member. Since the RTTI
                Packit 58578d
                  mechanism assumes that there is exactly one object of that member at
                Packit 58578d
                  runtime, the mechanism fails spectacularly when the process running the exe
                Packit 58578d
                  also loads the dll. Different platforms deal differently with this
                Packit 58578d
                  problem:

                Packit 58578d
                Packit 58578d
                  
                  Packit 58578d
                      
                • On some platforms (e.g. MinGW) there simply doesn't seem to be a way
                • Packit 58578d
                      to enforce that such a member only exists once at runtime. Therefore, the
                  Packit 58578d
                      internal RTTI mechanism cannot be used reliably in conjunction with DLLs.
                  Packit 58578d
                      Disabling it by defining 
                  Packit 58578d
                      "configuration.html#ApplicationDefinedMacros">BOOST_STATECHART_USE_NATIVE_RTTI
                  Packit 58578d
                      in all TUs will usually work around the problem
                  Packit 58578d
                  Packit 58578d
                      
                • MSVC-compatible compilers support __declspec(dllimport)
                • Packit 58578d
                      and __declspec(dllexport), which allow to define exactly
                  Packit 58578d
                      what needs to be loaded from a DLL (see TuTest for an example how to do
                  Packit 58578d
                      this). Therefore, the internal RTTI mechanism can be used but care must
                  Packit 58578d
                      be taken to correctly export and import all event<>
                  Packit 58578d
                      and simple_state<> subtypes defined in headers that
                  Packit 58578d
                      are compiled into more than one binary. Alternatively, of course 
                  Packit 58578d
                      "configuration.html#ApplicationDefinedMacros">BOOST_STATECHART_USE_NATIVE_RTTI
                  Packit 58578d
                      can also be used to save the work of importing and exporting
                  Packit 58578d
                    
                  Packit 58578d
                  Packit 58578d
                    

                  Does

                  Packit 58578d
                    Boost.Statechart support polymorphic events?
                  Packit 58578d
                  Packit 58578d
                    

                  No. Although events can be derived from each other to write common code

                  Packit 58578d
                    only once, reactions can only be
                  Packit 58578d
                    defined for most-derived events.

                  Packit 58578d
                  Packit 58578d
                    

                  Example:

                  Packit 58578d
                    
                  Packit 58578d
                  template< class MostDerived >
                  Packit 58578d
                  struct EvButtonPressed : sc::event< MostDerived >
                  Packit 58578d
                  {
                  Packit 58578d
                    // common code
                  Packit 58578d
                  };
                  Packit 58578d
                  Packit 58578d
                  struct EvPlayButtonPressed :
                  Packit 58578d
                    EvButtonPressed< EvPlayButtonPressed > {};
                  Packit 58578d
                  struct EvStopButtonPressed :
                  Packit 58578d
                    EvButtonPressed< EvStopButtonPressed > {};
                  Packit 58578d
                  struct EvForwardButtonPressed :
                  Packit 58578d
                    EvButtonPressed< EvForwardButtonPressed > {};
                  Packit 58578d
                  Packit 58578d
                  /* ... */
                  Packit 58578d
                  Packit 58578d
                  // We want to turn the player on, no matter what button we
                  Packit 58578d
                  // press in the Off state. Although we can write the reaction
                  Packit 58578d
                  // code only once, we must mention all most-derived events in
                  Packit 58578d
                  // the reaction list.
                  Packit 58578d
                  struct Off : sc::simple_state< Off, Mp3Player >
                  Packit 58578d
                  {
                  Packit 58578d
                    typedef mpl::list<
                  Packit 58578d
                      sc::custom_reaction< EvPlayButtonPressed >,
                  Packit 58578d
                      sc::custom_reaction< EvStopButtonPressed >,
                  Packit 58578d
                      sc::custom_reaction< EvForwardButtonPressed >
                  Packit 58578d
                    > reactions;
                  Packit 58578d
                  Packit 58578d
                    template< class MostDerived >
                  Packit 58578d
                    sc::result react( const EvButtonPressed< MostDerived > & )
                  Packit 58578d
                    {
                  Packit 58578d
                      // ...
                  Packit 58578d
                    }
                  Packit 58578d
                  };
                  Packit 58578d
                  Packit 58578d
                  Packit 58578d
                    

                  Why are

                  Packit 58578d
                    exit-actions called in the wrong order when I use multiple
                  Packit 58578d
                    inheritance?
                  Packit 58578d
                  Packit 58578d
                    

                  Update: The implementation has changed considerably in this area.

                  Packit 58578d
                    It is still possible to get this behavior under rare circumstances (when an
                  Packit 58578d
                    action propagates an exception in a state machine with orthogonal regions
                  Packit 58578d
                    and if the statechart layout satisfies certain conditions), but it
                  Packit 58578d
                    can no longer be demonstrated with the example program below. However, the
                  Packit 58578d
                    described workaround is still valid and ensures that this behavior will
                  Packit 58578d
                    never show up.

                  Packit 58578d
                  Packit 58578d
                    

                  They definitely aren't for the simple_state<> and

                  Packit 58578d
                    state<> subtypes, but the destructors of additional
                  Packit 58578d
                    bases might be called in construction order (rather than the reverse
                  Packit 58578d
                    construction order):

                  Packit 58578d
                    
                  Packit 58578d
                  #include <boost/statechart/state_machine.hpp>
                  Packit 58578d
                  #include <boost/statechart/simple_state.hpp>
                  Packit 58578d
                  Packit 58578d
                  namespace sc = boost::statechart;
                  Packit 58578d
                  Packit 58578d
                  class EntryExitDisplayer
                  Packit 58578d
                  {
                  Packit 58578d
                    protected:
                  Packit 58578d
                      EntryExitDisplayer( const char * pName ) :
                  Packit 58578d
                        pName_( pName )
                  Packit 58578d
                      {
                  Packit 58578d
                        std::cout << pName_ << " entered\n";
                  Packit 58578d
                      }
                  Packit 58578d
                  Packit 58578d
                      ~EntryExitDisplayer()
                  Packit 58578d
                      {
                  Packit 58578d
                        std::cout << pName_ << " exited\n";
                  Packit 58578d
                      }
                  Packit 58578d
                  Packit 58578d
                    private:
                  Packit 58578d
                      const char * const pName_;
                  Packit 58578d
                  };
                  Packit 58578d
                  Packit 58578d
                  struct Outer;
                  Packit 58578d
                  struct Machine : sc::state_machine< Machine, Outer > {};
                  Packit 58578d
                  struct Inner;
                  Packit 58578d
                  struct Outer : EntryExitDisplayer, sc::simple_state<
                  Packit 58578d
                    Outer, Machine, Inner >
                  Packit 58578d
                  {
                  Packit 58578d
                    Outer() : EntryExitDisplayer( "Outer" ) {}
                  Packit 58578d
                  };
                  Packit 58578d
                  Packit 58578d
                  struct Inner : EntryExitDisplayer,
                  Packit 58578d
                    sc::simple_state< Inner, Outer >
                  Packit 58578d
                  {
                  Packit 58578d
                    Inner() : EntryExitDisplayer( "Inner" ) {}
                  Packit 58578d
                  };
                  Packit 58578d
                  Packit 58578d
                  int main()
                  Packit 58578d
                  {
                  Packit 58578d
                    Machine myMachine;
                  Packit 58578d
                    myMachine.initiate();
                  Packit 58578d
                    return 0;
                  Packit 58578d
                  }
                  Packit 58578d
                  Packit 58578d
                  Packit 58578d
                    

                  This program will produce the following output:

                  Packit 58578d
                    
                  Packit 58578d
                  Outer entered
                  Packit 58578d
                  Inner entered
                  Packit 58578d
                  Outer exited
                  Packit 58578d
                  Inner exited
                  Packit 58578d
                  Packit 58578d
                  Packit 58578d
                    

                  That is, the EntryExitDisplayer base class portion

                  Packit 58578d
                    of Outer is destructed before the one of Inner
                  Packit 58578d
                    although Inner::~Inner() is called before
                  Packit 58578d
                    Outer::~Outer(). This somewhat counter-intuitive behavior is
                  Packit 58578d
                    caused by the following facts:

                  Packit 58578d
                  Packit 58578d
                    
                    Packit 58578d
                        
                  • The simple_state<> base class portion of
                  • Packit 58578d
                        Inner is responsible to destruct Outer
                    Packit 58578d
                    Packit 58578d
                        
                  • Destructors of base class portions are called in the reverse order of
                  • Packit 58578d
                        construction
                    Packit 58578d
                      
                    Packit 58578d
                    Packit 58578d
                      

                    So, when the Outer destructor is called the call stack

                    Packit 58578d
                      looks as follows:

                    Packit 58578d
                      
                    Packit 58578d
                    Outer::~Outer()
                    Packit 58578d
                    simple_state< Inner, ... >::~simple_state()
                    Packit 58578d
                    Inner::~Inner()
                    Packit 58578d
                    Packit 58578d
                    Packit 58578d
                      

                    Note that Inner::~Inner() did not yet have a chance to

                    Packit 58578d
                      destroy its EntryExitDisplayer base class portion, as it first
                    Packit 58578d
                      has to call the destructor of the second base class. Now
                    Packit 58578d
                      Outer::~Outer() will first destruct its simple_state<
                    Packit 58578d
                      Outer, ... > base class portion and then do the same with its
                    Packit 58578d
                      EntryExitDisplayer base class portion. The stack then unwinds
                    Packit 58578d
                      back to Inner::~Inner(), which can then finally finish by
                    Packit 58578d
                      calling EntryExitDisplayer::~EntryExitDisplayer().

                    Packit 58578d
                    Packit 58578d
                      

                    Luckily, there is an easy work-around: Always let

                    Packit 58578d
                      simple_state<> and state<> be the
                    Packit 58578d
                      first base class of a state. This ensures that destructors of additional
                    Packit 58578d
                      bases are called before recursion employed by state base destructors can
                    Packit 58578d
                      alter the order of destruction.

                    Packit 58578d
                      
                    Packit 58578d
                    Packit 58578d
                      

                    Packit 58578d
                      "../../../doc/images/valid-html401.png" alt="Valid HTML 4.01 Transitional"
                    Packit 58578d
                      height="31" width="88">

                    Packit 58578d
                    Packit 58578d
                      

                    Revised 05 January, 2008

                    Packit 58578d
                    Packit 58578d
                      

                    Copyright © 2003-2008 Andreas Huber

                    Packit 58578d
                      Dönni

                    Packit 58578d
                    Packit 58578d
                      

                    Distributed under the Boost Software License, Version 1.0. (See

                    Packit 58578d
                      accompanying file LICENSE_1_0.txt or
                    Packit 58578d
                      copy at 
                    Packit 58578d
                      "http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt)

                    Packit 58578d
                    </body>
                    Packit 58578d
                    </html>