Initializing array of objects within different class constructor

I’d like to create a class that uses an array of objects with the array size set in the constructor. The first way I tried seems to work (Serial outputs what I expect) but the IDE issues a warning about an unused variable. My 2nd attempt uses a pointer to the array with which the IDE is content (no warnings) but it uses fair bit more flash and a little more RAM. With neither technique does the IDE report the expected changes in RAM usage with a larger/smaller array because I think the compiler thinks it doesn’t know the size of the array even though I pass a constant to my constructor.

Attached is the full sketch for my 1st technique with the compiler warning and my 2nd technique with the pointer. You’ll need the Streaming library install-able via the built-in library manager or comment out those lines.

SensorReadings_class.ino (3.23 KB)

SensorReadings_class_pointer.ino (3.24 KB)

The only differences between the sketches is the array variable.

    SensorReadings(uint8_t _maxSensors){
      maxSensors = _maxSensors;
      Sensor sensors[maxSensors];
    }

    Sensor sensors[];

vs

    SensorReadings(uint8_t _maxSensors){
      maxSensors = _maxSensors;
      sensors = new Sensor[maxSensors];
    }

    Sensor *sensors;

You codes are small enough to post in-line (just like you did with the snippets). Please do so.

1st technique, compiles to 3042 bytes program & 321 bytes RAM.

#include <Streaming.h>

class Sensor{
  public:
    byte sensorNum;
    byte binNum;
    int value;
    // Comparison operator for two TempReading objects, will sort according to '>'. Without it, the IDE does not know what to compare
    // Sort priority 1 = bin ID, priority 2 = sensor ID
    boolean operator> (const Sensor &rhs){
      return ((binNum << 8) + sensorNum) > ((rhs.binNum << 8) + rhs.sensorNum); // combine the bin ID and sensor ID and compare both together
    }
};

#define MAX_LIMIT_REACHED -1

class SensorReadings{
  public:
    SensorReadings(uint8_t _mSensors){
      mSensors = _mSensors;
      Sensor sensors[mSensors];
    }
    int8_t addSensor(int16_t _value, uint8_t _binNum, uint8_t _sensorNum){
      if (nSensors > 0){
        if (debug) Serial << "\nSearching existing data, ";
        for (byte i = 0; i < nSensors; ++i){
          if (sensors[i].binNum == _binNum && sensors[i].sensorNum == _sensorNum){
            if (debug) Serial << "Old data updated";
            sensors[i].value = _value;
            return i;
          }
        }
        if (nSensors < mSensors){
          return addNewSensor(_value, _binNum, _sensorNum);
        } else {
          if (debug) Serial << "MAX LIMIT REACHED!!";
          return MAX_LIMIT_REACHED;
        }
      } else {
        return addNewSensor(_value, _binNum, _sensorNum);
      }
      return 0;
    }
    int8_t addNewSensor(int16_t _value, uint8_t _binNum, uint8_t _sensorNum){
      sensors[nSensors].binNum = _binNum;
      sensors[nSensors].sensorNum = _sensorNum;
      sensors[nSensors].value = _value;
      nSensors++;
      if (debug) Serial << "New data added";
      return nSensors - 1;
    }
    void sortSensors(){
      if (debug) Serial << "\n\nSorting sensors";
      boolean swapped;
      Sensor temp;
      do{
        swapped = false;
        for (byte i = 0; i < nSensors - 1; ++i){
          if (sensors[i] > sensors[i+1]){
            temp = sensors[i];
            sensors[i] = sensors[i + 1];
            sensors[i + 1] = temp;
            swapped = true;
          }
        }
      } while (swapped);
    }
    void printSensors(Print* _destination){
      if (debug) Serial << "\n\nPrinting sensors";
      for (byte i = 0; i < nSensors; i++){
        _destination->print(F("\nSensor "));
        _destination->print(sensors[i].binNum);
        _destination->print(":");
        _destination->print(sensors[i].sensorNum);
        _destination->print(F(" = "));
        _destination->print(sensors[i].value, DEC);
        _destination->print(F("."));
        _destination->print(abs(sensors[i].value%10),DEC);
        _destination->print(F(" C"));
      }
    }
    byte debug = 0;

  private:
    uint8_t mSensors;
    uint8_t nSensors = 0;
    Sensor sensors[];
};

const uint8_t numSensors = 3;
SensorReadings sensorReadings(numSensors);

void setup() {
  Serial.begin(115200);
  Serial << "\n\n***begin***\n\n";
  
  sensorReadings.addSensor(5, 1, 3);
  sensorReadings.addSensor(55, 1, 1);
  sensorReadings.addSensor(100, 1, 2);
  sensorReadings.addSensor(155, 1, 1);
  sensorReadings.addSensor(-55, 1, 4);
  sensorReadings.addSensor(-105, 1, 5);
  
  sensorReadings.printSensors(&Serial);
  sensorReadings.sortSensors();
  sensorReadings.printSensors(&Serial);
}

void loop() {
  while(1);
}

Using a pointer, compiles to 3722 bytes program & 333 bytes RAM.

#include <Streaming.h>

class Sensor{
  public:
    byte sensorNum;
    byte binNum;
    int value;
    // Comparison operator for two TempReading objects, will sort according to '>'. Without it, the IDE does not know what to compare
    // Sort priority 1 = bin ID, priority 2 = sensor ID
    boolean operator> (const Sensor &rhs){
      return ((binNum << 8) + sensorNum) > ((rhs.binNum << 8) + rhs.sensorNum); // combine the bin ID and sensor ID and compare both together
    }
};

#define MAX_LIMIT_REACHED -1

class SensorReadings{
  public:
    SensorReadings(uint8_t _mSensors){
      mSensors = _mSensors;
      sensors = new Sensor[mSensors];
    }
    int8_t addSensor(int16_t _value, uint8_t _binNum, uint8_t _sensorNum){
      if (nSensors > 0){
        if (debug) Serial << "\nSearching existing data, ";
        for (byte i = 0; i < nSensors; ++i){
          if (sensors[i].binNum == _binNum && sensors[i].sensorNum == _sensorNum){
            if (debug) Serial << "Old data updated";
            sensors[i].value = _value;
            return i;
          }
        }
        if (nSensors < mSensors){
          return addNewSensor(_value, _binNum, _sensorNum);
        } else {
          if (debug) Serial << "MAX LIMIT REACHED!!";
          return MAX_LIMIT_REACHED;
        }
      } else {
        return addNewSensor(_value, _binNum, _sensorNum);
      }
      return 0;
    }
    int8_t addNewSensor(int16_t _value, uint8_t _binNum, uint8_t _sensorNum){
      sensors[nSensors].binNum = _binNum;
      sensors[nSensors].sensorNum = _sensorNum;
      sensors[nSensors].value = _value;
      nSensors++;
      if (debug) Serial << "New data added";
      return nSensors - 1;
    }
    void sortSensors(){
      if (debug) Serial << "\n\nSorting sensors";
      boolean swapped;
      Sensor temp;
      do{
        swapped = false;
        for (byte i = 0; i < nSensors - 1; ++i){
          if (sensors[i] > sensors[i+1]){
            temp = sensors[i];
            sensors[i] = sensors[i + 1];
            sensors[i + 1] = temp;
            swapped = true;
          }
        }
      } while (swapped);
    }
    void printSensors(Print* _destination){
      if (debug) Serial << "\n\nPrinting sensors";
      for (byte i = 0; i < nSensors; i++){
        _destination->print(F("\nSensor "));
        _destination->print(sensors[i].binNum);
        _destination->print(":");
        _destination->print(sensors[i].sensorNum);
        _destination->print(F(" = "));
        _destination->print(sensors[i].value, DEC);
        _destination->print(F("."));
        _destination->print(abs(sensors[i].value%10),DEC);
        _destination->print(F(" C"));
      }
    }
    byte debug = 0;

  private:
    uint8_t mSensors;
    uint8_t nSensors = 0;
    Sensor *sensors;
};

const uint8_t numSensors = 3;
SensorReadings sensorReadings(numSensors);

void setup() {
  Serial.begin(115200);
  Serial << "\n\n***begin***\n\n";
  
  sensorReadings.addSensor(5, 1, 3);
  sensorReadings.addSensor(55, 1, 1);
  sensorReadings.addSensor(100, 1, 2);
  sensorReadings.addSensor(155, 1, 1);
  sensorReadings.addSensor(-55, 1, 4);
  sensorReadings.addSensor(-105, 1, 5);
  
  sensorReadings.printSensors(&Serial);
  sensorReadings.sortSensors();
  sensorReadings.printSensors(&Serial);
}

void loop() {
  while(1);
}

Changing numSensors in either sketch does not change the reported program memory & RAM usage which makes we think I’m not doing it correctly and I might have overrun issues later. What is the correct way to do this?

FYI: I added const uint8_t numSensors = 3; to both sketches.

This is pointless:

    SensorReadings(uint8_t _mSensors) {
      mSensors = _mSensors;
      Sensor sensors[mSensors];
    }

It creates an array of Sensor objects as a local variable in the constructor (stack variable). That array ceases to exist after the constructor function exits.

This is valid:

    SensorReadings(uint8_t _mSensors){
      mSensors = _mSensors;
      sensors = new Sensor[mSensors];
    }

But, since the array is created dynamically, its RAM usage will not show up in the compiler's report.

gfvalvo:
This is pointless:

    SensorReadings(uint8_t _mSensors) {

mSensors = _mSensors;
     Sensor sensors[mSensors];
   }



It creates an array of Sensor objects as a local variable in the constructor (stack variable). That array ceases to exist after the constructor function exits.

If I remove Sensor sensors[mSensors]; so that the constructor is only

   SensorReadings(uint8_t _mSensors){
      mSensors = _mSensors;
    }

I still get the results I expect. How does it know the size of the array if the variable is declared as only Sensor sensors[];? Am I correct in thinking that it doesn't and there's going to be problems later on even though the compiler is happy?

m_elias:
Am I correct in thinking that it doesn't and there's going to be problems later on even though the compiler is happy?

I believe that is correct.

gfvalvo:
I believe that is correct.

Thanks for your time!