Vous êtes sur la page 1sur 7

c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution?

- Code Review Stack Exchange

sign up

Code Review
beta

Questions

log in

Tags

tour

help

Users

search

Badges

Unanswered

Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no
registration required.

Ask Question

Take the 2-minute tour

State pattern + C++ template == short and elegant hierarchical FSM solution?
C++11/g++ 4.8 update

asked

1 year ago

viewed 3834 times

12

If anybody is interested, inherited constructors from C++11 are a real game changer for the solution
exposed here. I have just upgraded from g++ 4.6 and to 4.8, that has better support for C++11. I
am so happy I did!
I am able to change the ugly

explicit LevelState(Machine &m, StateRef<LevelState> &state) :


GenericState<Machine, LevelState>(m, state) {}

active

1 year ago

Blog

Introducing Beyond Coding:


Free professional skills training
for emerging dev

into the neat


using GenericState::GenericState;

Since a state machine can contain many abstract and concrete states, that makes the whole code
much more readable.
The code below reflects this change.

Introduction
The code below finds its origin in the following reflection.
In their book from 1995, the so-called gang of four (GoF) described the state pattern. What they
were actually telling us in their description, is that any object oriented language that implements
dynamic polymorphism has an embedded finite state machine (FSM) engine. C++ is such a
language, and the example code in the book is written in that language. Why then, do we have to
use large frameworks, libraries and tools in order to implement state machines in C++?
I asked myself that question recently for a C++ project where I have the freedom to choose my
tools. Since I have long been a supporter of the KISS-principle (keep it simple stupid), my first
intention was to just apply the pattern as described in the book.
Basically, the state pattern tells us that the FSM should have a pointer member to a virtual state
class, always pointing to a specialization of that class, that represents the current concrete state. It
then delegates the events it receives to the state pointer, like this (quoting the book):
TCPConnection::ActiveOpen () {
_state->ActiveOpen(this);
}

Linked
5

A variant of state pattern +


C++ template FSM without
state creation/destruction
penalty

Related
5

Designing a state machine in


C++ using the STL

Developing a better state


pattern in C

A variant of state pattern +


C++ template FSM without
state creation/destruction
penalty

Hierarchical State Machine in


F#

State Design Pattern in


Python

10 Compile time decorator

pattern in C++ with templates


3

Designing simple state


machine in C++

Member function state


machine

Expressing computations on
values as State

State Transition Table

where TCPConnection is the FSM and ActiveOpen() is an event.


However, the event handlers look like this:
void TCPClosed::ActiveOpen (TCPConnection* t) {
// send SYN, receive SYN, ACK, etc.
}

ChangeState(t, TCPEstablished::Instance());

where TCPClosed and TCPEstablished are concrete states.

http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution[5/6/2015 8:09:08 AM]

Hot Network
Questions

Alphabet Number Matching

Is every abelian group a colimit of


copies of Z?

Move live SQL Server database to a


new server

c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange

Not so neat. I started to wonder if templates couldn't help me to parametrize the target state in
ChangeState(). If the state had both a reference to the FSM and the ability to transform itself as a
result of a transition, surely I would get a much simpler and cleaner syntax.

Example FSM
Let's assume that I have the following silly state machine to implement (made with ArgoUML, if
anybody is curious).

silly state machine


It is silly, but it contains the features that, in my experience, are necessary in a state machine
implementation:
1. Entry, exit and transition actions.
2. Guards (conditional transitions).
3. Event parameters (a free event signature would be nice).
4. Composite states (states that contain sub-states).
5. Orthogonal states (also called and-states, which are semantically equivalent to separate
simultaneous FSMs, but it is sometimes necessary to run them in the same class). E.g.
LevelState and DirectionState are orthogonal states in the example.
6. Access to FSM members (variables or functions).
The UML has a lot more than that, but I am not convinced that the rest is strictly necessary in the
FSM implementation. After all, we have the rest of the programming language for that...

What I want is all you get


The kind of event handler I want is this:
void Machine::Red::paint(Machine::Color color)
{
if (color == BLUE)
change<Blue>();
}

where Machine is my FSM, Red the state, paint() the event, color an event parameter and Blue the
target state for the transition. But you knew all that, it's in the diagram.
As the code below testifies (public domain, use it as you wish, but don't blame me - compiles with
g++ 4.6, C++11 switched on), I have managed to implement the state machine depicted above, in
such a simple syntax, with the help of a 40-line state template that I have called GenericState

http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution[5/6/2015 8:09:08 AM]

Problem with bullying from an older


colleague

Should we define types for


everything?

more hot questions

c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange

(genericstate.h, the rest is the state machine code):


1. Entry and exit actions can be defined at any state level. Transition actions are programmed as
regular instructions in the event handlers before the actual state transitions. There is,
however, a difference with the UML in the order of execution: transition actions, exit actions
(old state), entry actions (new state). The UML has exit, transition actions, entry. But mine is
the same order as Miro Samek's model (http://www.state-machine.com/) - i.e. it is not
uncommon and there is nothing wrong with it as long as it is consistent.
2. Guards are regular "if" or "switch" statements in event handlers.
3. Event parameters are regular event handler arguments. The event handler signature is free
(and clutter-free).
4. Composite states are implemented by applying the same model recursively. In the sate
machine above, the state "Left" contains a "ColorState" virtual state that can be "Red" or
"Blue". However, when going from "Left" to "Right", the exit action from the current color will
not be executed (contrary to the UML semantics, but not a practical problem I believe).
5. Orthogonal states are managed by letting the FSM have several virtual state members instead
of just one ("LevelState" and "DirectionState" in "Machine" in the example).
6. Access to the FSM members is given to all states through the FSM reference "m" (e.g.
m.changedColor()).

Please comment
Any known similar implementation?
Any obvious bug or hazard?
Any obvious potential for improvement (performance, type safety in template use, etc.)?
It looks like I have unintentionally applied the so-called "curiously recurring template pattern".
Do you recognize any other pattern in my implementation? Any other pattern related
comment?
My implementation has a low RAM footprint (only one state instantiated at a time per FSM
instance and orthogonal region) but a certain runtime cost: every state transition will incur the
creation of a state instance and the destruction of another one on the heap. Comments about
that?
A reader of an earlier version commented off-line that my states were not flyweight as
described by GoF. This basically means that my state instances cannot be shared between
several state machine instances. I agree. I would not get such a simple syntax otherwise. I
think the trade off was worth it. Comments?
genericstate.h
#ifndef GENERICSTATE_H
#define GENERICSTATE_H
#include <memory>
template <class State>
using StateRef = std::unique_ptr<State>;
template <typename StateMachine, class State>
class GenericState
{
public:
explicit GenericState(StateMachine &m, StateRef<State> &state) :
m(m), state(state) {}
template <class ConcreteState>
static void init(StateMachine &m, StateRef<State> &state) {
state = StateRef<State>(new ConcreteState(m, state));
state->entry();
}
protected:
template <class ConcreteState>
void change() {
exit();
init<ConcreteState>(m, state);
}
void reenter() {

http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution[5/6/2015 8:09:08 AM]

c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange

exit();
entry();

private:
virtual void entry() {}
virtual void exit() {}
protected:

machine.h
#ifndef MACHINE_H
#define MACHINE_H
#include <string>
#include <iostream>
#include "genericstate.h"
class Machine
{
public:
Machine() {}
~Machine() {}
void start();
public:
enum Color {
BLUE,
RED
};
public:
void
void
void
void
void

liftUp() { levelState->liftUp(); }
bringDown() { levelState->bringDown(); }
paint(Color color) { directionState->paint(color); }
turnRight() { directionState->turnRight(); }
turnLeft() { directionState->turnLeft(); }

private:
static void print(const std::string &str) { std::cout << str << std::endl; }
static void unhandledEvent() { print("unhandled event"); }
void changedColor() { print("changed color"); }
private:
struct LevelState : public GenericState<Machine, LevelState> {
using GenericState::GenericState;
virtual void liftUp() { unhandledEvent(); }

machine.cpp
#include "machine.h"
void Machine::start()
{
LevelState::init<High>(*this, levelState);
DirectionState::init<Left>(*this, directionState);
}
void Machine::Red::paint(Machine::Color color)
{
if (color == BLUE) change<Blue>();
else ColorState::paint(color);
}
void Machine::Blue::paint(Machine::Color color)
{
if (color == RED) change<Red>();
else ColorState::paint(color);
}

main.cpp
#include "machine.h"
int main()

http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution[5/6/2015 8:09:08 AM]

c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange

Machine m;
m.start();
m.bringDown();
m.bringDown();
m.liftUp();
m.liftUp();
m.turnRight();
m.paint(Machine::BLUE);
m.turnLeft();
m.paint(Machine::RED);
m.paint(Machine::BLUE);

return 0;

Output from the program


entering High
changed color
leaving High
entering Low
already Low
leaving Low
entering High
already High
unhandled event
changed color
unhandled event
changed color
c++

c++11

state

state-machine

share improve this question

edited Feb 15 '14 at 1:33

community wiki

20 revs, 2 users 87%


nilo

Here is a TM in C++: stackoverflow.com/a/275295/14065

Loki Astari
Feb 4 '14 at 16:05
@LokiAstari: I certainly have much more to learn about C++ templates and the whole discussion seems really
interesting. Perfect bedtime reading, although it may keep me awake far too late :-)

nilo
Feb 4 '14 at
19:32
add a comment

1
Answer

active

oldest

votes

I don't have much to say.

Your implementation is similar to the GoF's (posted here) except that your machine instance is
passed by reference to the states' constructors, instead of being passed-in to the states' statetransition methods.
Advantage: cleaner syntax of the state-transition method
Disadvantage: state instances can't be flyweights
I wonder whether the following would allow a similarly-clean syntax but allow states to be
flyweights:
class LevelState {
public:
virtual LevelState* liftUp() = 0;
virtual LevelState* bringDown() = 0;
};
class HighLevelState : public LevelState {
public:

http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution[5/6/2015 8:09:08 AM]

c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange

LevelState* liftUp() { print("already High"); return this; }


LevelState* bringDown() { print("leaving High"); return LowLevelState::enter(); }
static LevelState* enter() { print("entering High"); return &singleton; }
private:
static HighLevelState singleton;
};
class Machine
{
public:
Machine() { levelState = LowLevelState::enter(); }
~Machine() {}
void liftUp() { levelState = levelState->liftUp(); }
void bringDown() { levelState = levelState->bringDown(); }
private:
LevelState* levelState;
};

This has some of the same advantages as your scheme (clean state methods) but also allows
singleton/flyweight states.
Heap operations can be relatively expensive; and I imagine that some state machines (for example,
the tokenizer of a parser) might want to be as fast as possible.
IMO a benefit of your scheme is when the state instances should carry state-specific data. For
example, perhaps the TCPEstablished state has associated data which needs to be stored
somewhere. If the state is a flyweight then that data must be stored in the machine; but maybe the
machine has many states, each with state-specific data, and it's not appropriate for the machine to
contain data for the states which it's not in at the moment: in that case you may want state-specific
data for the machine in the state instance => state is not a flyweight.
share improve this answer

edited Feb 11 '14 at 0:48

answered Feb 11 '14 at 0:12


ChrisW
11.4k

18

64

Thanks a lot. That's exactly the kind of reply I was hoping for.

nilo
Feb 11 '14 at 11:35
However, it looks to me that what makes my solution non-flyweight is the reference to the FSM and state
reference in the state. Making singletons of concrete states won't help that. In fact, it will in practice make my
FSM a singleton, which does not fulfill my need.

nilo
Feb 11 '14 at 11:40
Yes, your solution is incompatible with flyweight states, unless you machine is also a singleton. BTW I noticed
that (in your example use case) you hardly use the m member of your GenericState . GenericState is
mostly only using StateRef<State> &state i.e. states contain a reference to the unique_ptr in which
they're contained, so that they can change themselves.

ChrisW
Feb 11 '14 at 11:46
True about m. It's not supposed to be used in GenericState. It's supposed to be used in concrete states (and
is in my example). That why it's protected and not private.

nilo
Feb 11 '14 at 11:52

1 @nilo I don't think leaf states need to 'forward events they don't care about' to their superclass. If they don't
care about an event then they simply don't override the corresponding virtual function, so that virtual function
is only defined/handled in the superclass.

ChrisW
Feb 11 '14 at 15:08
show 7 more comments

Your Answer

http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution[5/6/2015 8:09:08 AM]

c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange

Post Your Answer

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged

c++

c++11

state

state-machine

or ask your own question.

question feed

tour
help
blog
chat
data
legal
privacy policy
work here
advertising info
mobile
contact us
feedback

TECHNOLOGY

LIFE / ARTS

Stack Overflow

Programmers

Server Fault

Unix & Linux

Database
Administrators

Super User

Ask Different (Apple)

Web Applications

WordPress
Development

Ask Ubuntu
Webmasters

Geographic Information
Systems

Game Development

Electrical Engineering

TeX - LaTeX

Android Enthusiasts
Information Security

Photography

CULTURE /
RECREATION
English Language &
Usage

SCIENCE

OTHER

Mathematics

Stack Apps

Cross Validated (stats)

Meta Stack Exchange


Area 51

Drupal Answers

Science Fiction &


Fantasy

SharePoint

Graphic Design

Mi Yodeya (Judaism)

Theoretical Computer
Science

User Experience

Seasoned Advice
(cooking)

Travel

Physics

Christianity

MathOverflow

Arqade (gaming)

more (7)

Mathematica
Salesforce

more (14)

Home Improvement

Skeptics

Personal Finance &


Money

Bicycles

Academia

Role-playing Games

more (10)

more (21)

site design / logo 2015 stack exchange inc; user contributions licensed under cc by-sa 3.0 with attribution required

rev 2015.5.5.2552

http://codereview.stackexchange.com/questions/40686/state-pattern-c-template-short-and-elegant-hierarchical-fsm-solution[5/6/2015 8:09:08 AM]

Stack Overflow Careers

Vous aimerez peut-être aussi