1

My state machine handles requests and returns the next state. In the below simplification, I've got two states here, CreatedState and RunningState. Running state is the end state, and just returns itself. Running state has state (as in memebers) that need to be preseved, I'll use the integer count to represent them.

std::unique_pointer<StateBase> handle();

// Caller
void Call(){
    _currentState = _currentState->handle();
}

// Created State Implementation
std::unique_pointer<StateBase> CreatedState::handle(){
    return std::make_unique<RunningState>();
}

// Running State Implementation (option 1: create a new one)
std::unique_pointer<StateBase> RunningState::handle(){
    return std::make_unique<RunningState>(RunningState(int count));
}

The problem here is that creating a new RunningState with a memento/all-of-the-private-members of the old RunningState is messy and probably inefficient(?).

In a managed language I might just return this, but if I did something like that: return std::make_unique<RunningState>(&this) I would have two pointers to the same object and the destruction of the lhs _currentState in the Call() would leave me with nothing to point at.

How can I cleanly and efficiently leave _currentState unchanged?

  • 1
    The std::enable_shared_from_this base class was originally designed to solve problems similar to this. However, I have yet to see practical use of it, so I can't comment on its efficacy. – rwong Oct 23 '15 at 9:28
  • std::make_unique<...>(this) does not merely point to the same object. It forwards the arguments to the constructor of the class, effectively copy-constructing another instance, taking your argument instance as the source of data. If you do not define any constructors for your class, C++ will implicitly define one for you. – rwong Oct 23 '15 at 9:41
  • @rwong Good point about the shared, might be the way to go. I do sort of feel that with reference counting pointers I'll be paying for a lot I don't use as well as allowing for slopper ownership by code calling my state machine (maybe that's a bad thing?). I see that my (this) C++ code is wrong, and probably still is, my State classes contain unique pointers and cannot be copied anyway. – Nathan Cooper Oct 23 '15 at 10:24
  • It seems you should just treat your design as usual polymorphism (or, non-polymorphism, if there's nothing in common), since it is unclear to me why you need to advance to next-state from a RunningState. In other words, the CreatedState has a reason to advance to next-state which is RunningState, but RunningState doesn't. – rwong Oct 23 '15 at 10:29
  • @rwong I don't think it's necessarily wrong to have a state machine with an end state. I understand how my simplified example doesn't really do that argument justice, however. I think I'll probably seek some more feedback from SO.CR about that when I'm done. Thanks for your help rwong. – Nathan Cooper Oct 23 '15 at 12:52
1

My potential solution:

Pass the pointer as a reference. Alter it in the handle as needed. I'm not a big fan of mutating parameters in general, but I think this might be the way to go?

#include <iostream>
#include <memory>

void handle2(std::unique_ptr<int>& current, bool changePtr)
{
    *current = *current + 5 ;
    if(changePtr){
    auto foo = std::make_unique<int>(200);
    (*foo)++;
    current = std::move(foo); //destruction of current only happens if I want to change state
    }
}

int main()
{
    auto currentState = std::make_unique<int>(50);

    handle2(currentState, false);
    std::cout << *currentState << std::endl; // 55
    // Guard against nullptr in caller      

    handle2(currentState, true);  
    std::cout << *currentState << std::endl; // 201

    handle2(currentState, false);    
    std::cout << *currentState << std::endl; // 206
}

Incidently, here is the state machine I was designing: https://github.com/mikeyjkmo/ableton-freetime-looper

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.