I am creating a state machine few states of which are switching the machine into a new (next) state in enter()
method. The states are a unique_ptr
objects which are created as needed and given to the machine.
As some states switch to the next state in enter()
method (thus, while being used) I am concerned about possible problems here - when the current state calls set_state()
the state machine assigns a new state to its state
member thus losing the only pointer to the state from which this call was made.
Below is an example of my concern - the only unique_ptr
for obj A and B is set to point to C while recursively calling this action from A and then B. Is this reliable? Will it cause any problems?
#include <memory>
#include <iostream>
class IState;
class IStateMachine {
public:
virtual ~IStateMachine() = default;
virtual void set_state(std::unique_ptr<IState> new_state) = 0;
};
class IState {
public:
virtual ~IState() = default;
virtual void enter(IStateMachine&) = 0;
};
class StateC : public IState {
public:
void enter(IStateMachine&) override {
std::cout << __func__ << ": StateC - start" << std::endl;
std::cout << __func__ << ": StateC - end" << std::endl;
}
};
class StateB : public IState {
public:
void enter(IStateMachine& sm) override {
std::cout << __func__ << ": StateB - start" << std::endl;
sm.set_state(std::make_unique<StateC>());
std::cout << __func__ << ": StateB - end" << std::endl;
}
};
class StateA : public IState {
public:
void enter(IStateMachine& sm) override {
std::cout << __func__ << ": StateA - start" << std::endl;
sm.set_state(std::make_unique<StateB>());
std::cout << __func__ << ": StateA - end" << std::endl;
}
};
class StateMachine : public IStateMachine {
public:
void start() {
set_state(std::make_unique<StateA>());
}
void set_state(std::unique_ptr<IState> new_state) {
state_ = std::move(new_state);
state_->enter(*this);
}
std::unique_ptr<IState> state_;
};
int main()
{
StateMachine sm;
sm.start();
}
The output from the code:
enter: StateA - start
enter: StateB - start
enter: StateC - start
enter: StateC - end
enter: StateB - end
enter: StateA - end
Edit 1:
The main idea behind is that the states are created as needed and automatically destroyed after they are not needed anymore.
The restriction is that a state may do some work in its enter()
method and then in the end of that method switch the state machine to the next state.
Edit 2:
I am not deleting the object explicitly. My question is more about lifetime of the object pointed to by a unique_ptr
in case when a new object assigned to this one unique_ptr
from the object`s own method (recursively) (see example code).