0

I have several classes that call each other running on an Arduino Mega. I am using the ArduinoSTL library to get the std library, most notably the std::vector.

The core problem is as follows: my Manager object that is created in the Arduino global space, is called in the loop(). The Manager object in one of it's functions spawns a derived object Derived derived (the constructor also takes a pin int and a delay value, but just simplifying for now) and calls a function in it derived.startExecution(). All is happy. Then I store a pointer to the object into a std::vector<base*> myVector via myVector.push_back(&derived). All is happy. As long as I don't leave the function, I can then take the pointer out of the vector container and call another function in the object. For example: myVector.back()->continueExecution() and all is great. Now the problem. If I copy paste the line myVector.back()->continueExecution() into a different function, the Arduino restarts. I'm losing my sanity here. I know that the issue is not the pointer, but the call to the function using the pointer. Using println & delay(500), in a new function inside the Manager I can do the following without issue (no restart):

  • retrieve pointer from vector. All good.
  • assign pointer from vector to a temporary pointer type to be able to refer to that pointer. All good
  • calling the function in the object causes instant Arduino Hardware reset (not a single line will execute in the function that is called).

All this leads me to the conclusion that calling the function in the object is causing a problem. I rewrote a simplified version of the code below, and it executes well on this website (please see: https://godbolt.org/z/G3x556), but on the Arduino it crashes.

What can I do to understand why the object crashes the program? how can I validate that the object is OK prior to calling the function? Why does the call to the function in an object that should be alive crashes the system? why does the call work in the function which stored it in the vector, but not in a different function? How can I answer these questions. I have hit a limit on ideas. Thank you for your time!

My code simplified:

#include <iostream>
//#include <ArduinoSTL.h> //commented out to work on website
#include <vector>

//base class is used to be able to push everything into a std::vector
//in ArduinoSTL lib.
class Base
{
    public:
        virtual void continueExecution() 
        { std::cout << "Base" << std::endl; }

        // a polymorphic class MUST have a virtual destructor
        virtual ~Base(){};
};

//lots of these classes will exist one day if I keep at this grind
class Derived : public Base
{
    public:
        Derived()
        {
            std::cout<< "Derived constructor" << std::endl;
        }

        void startExecution()
        {
            std::cout << "Derived object, start function"<< std::endl;
            //start work
        }

        void continueExecution()
        { 
            //continue when time has eleapsed
            std::cout << "Derived continueExectution " << std::endl; 
        }
};

class Manager
{
    public:
        void beginExecutingDerivedObject()
        {
    
            //derived object
            Derived derivedObj;

            derivedObj.startExecution();

            myVector.push_back(&derivedObj);

            //if I run the line that crashes the code below this
            //comment, all is OK. But that is not where it is needed.
            myVector.back()->continueExecution();
        }

        void finishExecutionOfDerivedObject()
        {
            //CODE CRASH HERE. The moment the function is called, a reset
            //occurs.
            myVector.back()->continueExecution();

            //any code here may appear on the console, but it's just a 
            //memory dump. By this point, the Arduino has thrown up it's arms.
        }            

    private:
        //create vector
        std::vector<Base*> myVector;   
};


//main is actually the arduino loop()
int main()
{
    //this manager class is in the sketch global space
    Manager manager;

    //this is called by a function call in the loop()
    manager.beginExecutingDerivedObject();

    //this is also called by a function call in the loop()
    manager.finishExecutionOfDerivedObject();
}

1 Answer 1

4

Derived derivedObj; is a local variable. It's deleted when the function exits. You have saved a pointer to it, but with that object now gone your pointer points to nothing of any interest - so doing anything with it is doomed to failure.

Instead you need to create a new object on the heap, which will already be a pointer:

Derived *derivedObj = new Derived();
derivedObj->startExecution();
myVector.push_back(derivedObj);

And then be sure to delete any objects you remove from the vector or you'll have lost that memory forever.

7
  • Note that std::vector<Base*> myVector; is a vector of pointers. You could store values in a vector as std::vector<Base> myVector;, but then you cannot store instances of derived classes.
    – PMF
    Jan 25, 2021 at 20:53
  • @Mike In your case, it's a bit complicated, because you have to do it when you remove elements or clear the myVector list. (Iterate over it with a for loop and delete all elements before you clear the vector). Using the STL (and some of the other features you use above) is quite advanced stuff for running on an Arduino, just because it's memory is very limited. You should probably look at some C++ tutorials first and run a few test programs on the PC first (where it's much easier to debug).
    – PMF
    Jan 25, 2021 at 20:58
  • A C++11 shared_ptr smart pointer makes it easier, but no idea if ArduinoSTL supports them.
    – Majenko
    Jan 25, 2021 at 20:59
  • @Majenko You ROCK!!! I don't know C++ at all and it's so hard to learn on the fly. Thanks a ton for your answer. Could I push my luck and please ask for an example on how to use the delete word? I'm totally new to C++ and really appreciate it. Could your example please assume C++99 is being used (if I'm lucky enough to get one)?
    – Mike
    Jan 25, 2021 at 21:19
  • Base *ob = myVector[0]; myVector.erase(0); delete ob;
    – Majenko
    Jan 25, 2021 at 21:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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