You could indeed use a std::vector
to eliminate the need for a maximum capacity, but dynamically growing a vector is not ideal on a microcontroller.
I'd suggest the following:
- Create a struct
DoublyLinkable
with anext
andprev
pointer. - Create a
DoublyLinkedList
class to maintain a linked list of suchDoublyLinkable
nodes, with operations to insert or remove nodes from the list. - Make your class inherit from
DoublyLinkable
. - Add a static
DoublyLinkedList
to your class. - Add each instance to the list in the constructor of your class, remove it from the list in the destructor.
This approach requires no dynamically allocated storage, just one or two extra pointers in each instance. If you don't have specific requirements on the order, you can use a singly linked list.
You can find an implementation here:
DoublyLinkable
andDoublyLinkedList
: Arduino-Helpers/src/AH/Containers/LinkedList.hpp at master · tttapa/Arduino-Helpers · GitHub- Class that automagically keeps track of all instances: Arduino-Helpers/src/AH/Containers/Updatable.hpp at master · tttapa/Arduino-Helpers · GitHub
Example:
#include <Arduino_Helpers.h>
#include <AH/Containers/Updatable.hpp> // UpdatableCRTP
#include <AH/STL/memory> // make_unique
struct DummyClass : UpdatableCRTP<DummyClass> {
const char *name;
DummyClass(const char *name) : name(name) {}
// Some function that does something
void print(const char *msg) { Serial << name << " says " << msg << endl; }
// Call the “print” function for all active instances
static void printAll(const char *msg) {
applyToAll(&DummyClass::print, msg);
Serial.println();
}
// Get the list of all active instances
static DoublyLinkedList<DummyClass> &instances() { return updatables; }
};
void setup() {
Serial.begin(115200);
while (!Serial);
// Create two instances
auto a = AH::make_unique<DummyClass>("A");
auto b = AH::make_unique<DummyClass>("B");
DummyClass::printAll("message 1");
// Disable the first instance
a->disable();
DummyClass::printAll("message 2");
// Enable the first instance
a->enable();
DummyClass::printAll("message 3");
// Delete the first instance
a.reset();
DummyClass::printAll("message 4");
{ // Create a scoped local instance
DummyClass c = "C";
DummyClass::printAll("message 5");
} // Local instance is deleted
DummyClass::printAll("message 6");
// Another instance
DummyClass d = "D";
// Iterate over all instances
Serial.print("Active instances: [ ");
for (DummyClass &inst : DummyClass::instances()) {
Serial << inst.name << ", ";
}
Serial.println("]");
}
void loop() {}
Output:
A says message 1
B says message 1
B says message 2
B says message 3
A says message 3
B says message 4
B says message 5
C says message 5
B says message 6
Active instances: [ B, D, ]
That would be exactly the same as a public: static
member function in C++. But like J-M-L said, it's often better to use free functions. Not everything has to be a class.
What makes you think that?
instance
is not a pointer, it cannot be null. Either way, never use NULL
, use nullptr
.
This is a memory leak.
Unlike in Java, you almost never use new
in C++. If you need dynamic allocations, use std::make_unique
. If you just want to create an object, allocate it on the stack (which is the default).
If you want to correct your code, you can find many C++ singleton classes online, but I don't think it will solve your problem.