Reset every instance of a member variable?

Hi everyone! Not sure the best way to ask this question within the context of my use-case while also keeping the code to a minimum, but I will try my best!

The Question:

Is there a way to reset each instance of a member variable without me as the programmer needing to remember every instance created?

Description

Let's say I have a variety of functions my robot will perform, such as walk, jump, shake hands, etc. Each function has a series of steps:

For example,

void jump()
{
 //Step 1: bend your legs so you're squatting. Once you're squatting, move to step 2
 //Step 2: quickly unbend your legs so you leap into the air, then move to step 3
 //Step 3: bend your legs again so that you have a gentle landing, the move to step 4
 //Step 4: slowly unbend your legs so you don't jump, but instead merely reset back to your original stance
}

Maybe not the greatest example, but the point is that I feel the need to have distinct "steps" within the function, because multiple motors and sensors may all need to perform tasks within a single step. jump() needs to be repeatedly called over and over again in the loop() function so that it can perform all the tasks in step 1, check that it's completed them, and then move to step 2, and so on.

So, since each of my functions needs to keep track of which "step" it is in, I'm thinking of creating a class called StepManager, allowing each function to have its own instance of "int step" to help manage which step it should perform.

Let's say I use a remote control to perform each of these commands (walk, jump, etc.), and have a master reset button.

The goal is that if the master reset button is pressed, the "int step" instance within each function needs to reset to 0. That way, each function will begin at step == 0 the next time it is called.

It seems that in order to reset each instance of "step", I might need to create a vector/container/list that keeps track of every instance created, but this seems unclean to me since all instances will be known during compiling. I feel this way because the only places where these instances exist are in the functions I pre-define, such as walk(), jump(), etc.

Is there another, possibly easier and/or better way to reset the "step" within each function?

Abstract Code example with a bit more context

class StepManager //a class that allows each function to have its own instance of "step"
{
  public:
    int step = 0;
    static void resetEveryInstanceOfStep()
    {
      //This is the question: is there a way to reset each instance of "int step" without me as the programmer needing to remember every instance created?
    }
};


void walk()
{
  static StepManager walkStep; //this static object will keep track of which "step" the function is in, even while the function is called over and over again

  if (walkStep.step == 0)
  {
    //do some stuff here
    function1step.step++;
  }
  else if (walkStep.step == 1)
  {
    //do some other stuff here
    walkStep.step++;
  }
  else if (walkStep.step == 2)
  {
    //do something different here
    walkStep.step++;
  }
}

void jump()
{
  static StepManager jumpStep; //this static object will keep track of which "step" the function is in, even while the function is called over and over again

  if (jumpStep.step == 0)
  {
    //do some stuff here
    jumpStep.step++;
  }
  else if (jumpStep.step == 1)
  {
    //do some other stuff here
    jumpStep.step++;
  }
  else if (jumpStep.step == 2)
  {
    //do something different here
    jumpStep.step++;
  }
}

void setup()
{
  
}

void loop()
{
  if (userIsHoldingDownButton1() == true) //while the user is holding down this button, run function1()
  {
    function1(); //continuously call function1(), which will cycle through each of the steps within function1()
  }
  else if (userIsHoldingDownButton2() == true)
  {
    function2(); //continuously call function2(), which will cycle through each of the steps within function2()
  }
  
//imagine I have many more buttons, each which corresponds to its own function that contains many "steps" 
  
  
  if(masterResetButtonIsPressed() == true)
  {
    //StepManager::resetEveryInstanceOfStep();
   //This is the question: is there a way to reset each instance of "int step"
   // without me as the programmer needing to remember every instance created?  
  }
  
}

Any help and advice is appreciated!

I don't think this code does what you expect (and I know it's just pseudo code). It won't continuously loop through and set off multiple instances of function1. It will start function1 and won't continue until function1 has completed. So the way you've structured it there's no need to keep track of step numbers because every time any of your functions are called the previous function will be fully completed and you're ready to start at step1 each time anyway.

Edit: I might be misunderstanding. The first example code of the jump() function looks like it performs all the steps in order but later in the post the jump function only performs one step at a time

Nothing "unclean" about it. IMO, the easiest way would be a fixed-size array of pointers to instances.

class StepManager {
  public:
    StepManager() {
      for (auto &element : instancePointers) {
        if (element == nullptr) {
          element = this;
          break;
        }
      }
    }

    ~StepManager() {
      for (auto &element : instancePointers) {
        if (element == this) {
          element = nullptr;
          break;
        }
      }
    }

    static void resetAll() {
      for (auto &element : instancePointers) {
        if (element != nullptr) {
          element->resetInstance();
        }
      }
    }

  private:
    static constexpr size_t maxInstances = 10;
    static StepManager *instancePointers[maxInstances];

    void resetInstance() {
    }
};

StepManager * StepManager::instancePointers[maxInstances] = {nullptr};

Invoke it with:

  StepManager::resetAll();

Thank you both!!

@touch1337 I appreciate the reply, and I was worried my psuedo code may not articulate it well. I have written a more elaborate code example (and it compiles), but I think @gfvalvo has answered the question so rather than asking you to read my more elaborate code example, I will first give @gfvalvo's solution a try :slight_smile:

@gfvalvo thanks so much for your help on this thread and my other threads...your comment is reassuring, and you taking the time to actually show me the code within the context of my own code is really generous of you!

I can see you created an array with maxInstances = 10 (I'm assuming since I mentioned that I know how many instances exist prior to compiling)

And if I understand correctly (please let me know if I didn't), what's going to happen is that at any given time, there can be up to 10 instances that are being managed at any given time. Any instance that gets created beyond "10" will not be affected by resetAll().

So if I keep creating new functions that will also use the StepManager class, then my choices are:

  • Increase maxInstances each time I create a new type of function, or
  • Set maxInstances to some large value that I will never exceed, or
  • Rather than a fixed size array, create a vector instead

#2 is likely easiest. Since the array elements are just pointers, making maxInstances large isn't very expensive.

#3 would work. But it adds extra complexity without adding significant value.

ahh good point about #2 not being very expensive!

Thank you!!
So where do I send all these beers I owe you? :beers: :grin:

Will there be only a single "action" happening at a time? I.e., will the "walk" action always complete (or be reset to the first step) before the "jump" action starts? Or can you have, e.g., step 1 of "walk" followed by step 2 of "jump"?

If an action always completes or is reset to step 0 before another action starts, then you really need only one instance of StepManager. And if the only thing StepManager is managing is a single int member variable (the step itself), all you really need is a single shared instance of an int:

static int step = 0; // can be `static byte step = 0;` if there are no more than 256 steps in any single action

void jump() {
    switch (step) {
    case 0:
        // bend your legs
        ++step;
        break;
    case 1:
        // quickly unbend your legs
        ++step;
        break;
    // etc.
    }
}

void loop() {
    // ...
}

Thanks for the reply! That's a good point, I'll have to think really hard to see if there's a situation where "jump" could happen in between "walk". I doubt it.

However, there may be a situation where one function can be embedded into a larger function.

such as...

void PreProgrammedSequence()
{
//step 1: walk()
//step 2: jump()
//step 3: flash LED lights and Serial.print("I jumped!")
//step 4: walk()
//step 5: shakeHands()
}

So in this case, void PreProgrammedSequence() will need its own "step" variable that doesn't interfere with the "step" variable that is inside of walk(), jump(), etc.

So I figured maybe just having a class will be easier, where it's easy to make a new instance of StepManager as needed.

int step isn't the only thing I'm thinking of putting in that class. I also have a wait(int milliseconds) which will keep checking milis(), and then increment "step" when a certain amount of time has passed.

So that's another function that I would want to re-use for each of these functions.