Académique Documents
Professionnel Documents
Culture Documents
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
State pattern + C++ template == short and elegant hierarchical FSM solution?
C++11/g++ 4.8 update
asked
1 year ago
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
active
1 year ago
Blog
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
Related
5
Expressing computations on
values as State
ChangeState(t, TCPEstablished::Instance());
Hot Network
Questions
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).
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
c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange
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() {
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()
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;
c++11
state
state-machine
community wiki
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
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:
c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange
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
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
c++11 - State pattern + C++ template == short and elegant hierarchical FSM solution? - Code Review Stack Exchange
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
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
Database
Administrators
Super User
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
Drupal Answers
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
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