1

I have spent the better part of today trying to figure out why I can't get this to work...

I have this project where, because of previous design considerations, have implemented a singleton class that initializes a bunch of separate sensors in this system that I am running.

The system was originally built for the Particle Boron, but now I am trying to make it work with the Adafruit Feather M0, so I have had to refactor several things and omit lots of lines of Particle RTOS specific things.

However, in doing this, I find that my singleton class no longer works.

Sensors.h:

.
.
.

class Sensors{

static Sensors *instance;

public: static Sensors *getInstance() { if (!instance) { instance = new Sensors; } return instance; }

}

private: Sensors();

. . .

Sensors.cpp:

.
.
.

Sensors::Sensors() : dht22(DHTPIN, DHTTYPE) { #ifdef PLATFORM_ID sensorLog("app.Sensors"); #endif }

. . .

main.ino:

.
.
.

// Sensors Sensors Sensors::instance = nullptr; Sensors allSensors = allSensors->getInstance();

void setup(){

. . .

As I try to compile this with ArduinoISP, no matter what I try, I get the following error:

sketch/main.ino.cpp.o: in function `Sensors::getInstance()':
sketch/lib/Sensors/src/Sensors.h:23: undefined reference to `Sensors::Sensors()'
collect2: error: ld returned 1 exit status
exit status 1
[Error] Exit with code=1

I have tried things like changing the line

instance = new Sensor;

to

instance = new Sensor();

making the instance public, changing the Sensor constructor, but all of this to no avail. Could this be a compiler issue? Why would this work on a Particle board, but not an Adafruit Feather M0?

2 Answers2

1

I had the same problem when referencing classes from multiple files, remember to put at the top of your header file (ending in .h) #pragma once on files that get referenced more than once!

Edit1: Also after you declare your class you need to specify where your static variable will be stored. After the class declaration write:

type *Class::variable;

To declare the static variable.

For example:

#pragma once
//#includes

class Screen { protected: static void (StateMachineStep)(int); static SSOLED oled; static Player *player;

public: Screen() {}

};

void (Screen::StateMachineStep)(int); SSOLED Screen::oled; Player *Screen::player;

Edit2: formatting

Qubo
  • 31
  • 3
0

Singletons aren't a thing in Arduino. Sure, you could do it, but in general you'd make a class then instantiate a global object for that class. Most often that global object is instantiated in the library itself, not the sketch.

Unless you're using an advanced chip with an RTOS (such as ESP32) and making use of the threads of that RTOS heavily there is no benefit to having a singleton.

But to answer your actual question: it's probably because you are trying to use the Sensors() constructor at a time before the compiler knows what the Sensors() constructor is. You would have to add some form of forward declaration so that the compiler knows what you mean when you talk about the Sensors() constructor. In general a simple:

class Sensors;

at near the top of your header before the class is actually defined can help in these situations;

Majenko
  • 105,851
  • 5
  • 82
  • 139