Array of pointers to objects

Hi,
I’ve built array with Relay objects. Trying to refactor to be an array of pointers to objects how to make that code works:

#define RELAY_ARRAY_SIZE 1
Relay myRelay(&mqttClient, 5, “mqttCommand”);
Relay relays[RELAY_ARRAY_SIZE] = { myRelay };

void loop() {

for (int i=0; i < RELAY_ARRAY_SIZE; i++)
{
//THIS DO NOT WORK WHEN ITERATE ARRAY OBJECTS
relays[i].setAutoDisableTime(15000);
}

//THIS WORKS WHEN CALLING OBJECT DIRECTLY
myRelay.setAutoDisableTime(15000);
}

How should I construct that array to make that work?

The first element of your array is a COPY of ‘myRelay’. Changing that element will not change ‘myRelay’. To make it operate on myRelay you should use an array of pointers:

#define RELAY_ARRAY_SIZE 1
Relay myRelay(&mqttClient, 5, "mqttCommand");
Relay *relays[RELAY_ARRAY_SIZE] = { myRelay };
  
void loop() {

  for (int i=0; i < RELAY_ARRAY_SIZE; i++)
  {
     //THIS DO NOT WORK WHEN ITERATE  ARRAY OBJECTS
     relays\[i\]->setAutoDisableTime(15000);
  } 

     //THIS WORKS WHEN CALLING OBJECT DIRECTLY 
     myRelay.setAutoDisableTime(15000); 
}

But when trying to build pointers array:

button.ino:32:42: error: cannot convert 'Relay' to 'Relay*' in initialization

#define RELAY_ARRAY_SIZE 1
Relay *relays[RELAY_ARRAY_SIZE] = { new Relay(&mqttClient, 5, "mqttCommand") };

Regards,
Ray L.

lonas:
But when trying to build pointers array:

button.ino:32:42: error: cannot convert 'Relay' to 'Relay*' in initialization

John forgot the address-of operator:

Relay *relays[RELAY_ARRAY_SIZE] = { [color=orange]&[/color]myRelay };

RayLivingstons method is useful if you do not control when the relay is created. However if you do, dynamic memory is just an overhead.

Thanks!!
I would like to do next step :slight_smile:

I have class ButtonHandler where I would like to have as parameter pointer to my array.
I did try to many ways, can You tell me how to do this, please?

What I have is:

we in MAIN scatch we have an array with relays:
Relay *relays[RELAY_ARRAY_SIZE] = { &myRelay };

puting that into:
ButtonHandler buttonHandler(*relays, RELAY_ARRAY_SIZE);

also tried like that
ButtonHandler buttonHandler(&relays, RELAY_ARRAY_SIZE);

  • but still this do not work

I have class:

	class ButtonHandler
	{
		public:
		  ButtonHandler(Relay *relays, int arraySize);
		  void handle(String topic, String mqttCmmand);

		private:
		  Relay *relays;
		  int arraySize;
		  bool isButtonTopic(String topic);
                  void processCommand(String mqttCommand);
                  bool isMatch(String mqttCommand, String relayCommand);
	};

and cpp
#include "ButtonHandler.h"

ButtonHandler::ButtonHandler(Relay *relaysArg, int arraySizeArg) : relays(relaysArg), arraySize(arraySizeArg) {}
....

How can I have pointer to an array created in main scatch?

RayLivingston:

#define RELAY_ARRAY_SIZE 1

Relay *relays[RELAY_ARRAY_SIZE] = { new Relay(&mqttClient, 5, "mqttCommand") };

Now this defines an array of pointers to relay, and attempts to initoalise it with a realy object. This won't work.

If you are happy to simpy have an array of relay objects, then

#define RELAY_ARRAY_SIZE 1
Relay relays[RELAY_ARRAY_SIZE] = { Relay(&mqttClient, 5, "mqttCommand") };

Should do the job, I think.

Right but now how should I past that array into next class as pointer?

PaulMurrayCbr:

#define RELAY_ARRAY_SIZE 1

Relay *relays[RELAY_ARRAY_SIZE] = { new Relay(&mqttClient, 5, "mqttCommand") };



Now this defines an array of pointers to relay, and attempts to initoalise it with a realy object. This won't work.

It does work, new returns a pointer.

Ok but how to past that into another class as pointer?

ButtonHandler buttonHandler(relays, RELAY_ARRAY_SIZE);
we in MAIN scatch we have an array with relays:
Relay *relays[RELAY_ARRAY_SIZE] = { &myRelay };

puting that into:
ButtonHandler buttonHandler(*relays, RELAY_ARRAY_SIZE);  

also tried like that
ButtonHandler buttonHandler(&relays, RELAY_ARRAY_SIZE);

Since ButtonHandler is set up to take a pointer and relays is already a pointer you don't need any operator to pass it.

Just.

ButtonHandler buttonHandler(relays, RELAY_ARRAY_SIZE);

Ok but becasuse of some reasons it do not work like that and in ButtonHandler I have copy not a pointer.

Let me put full code.

Main sketch

#define RELAY_ARRAY_SIZE 2
Relay relays[RELAY_ARRAY_SIZE] = 
{ 
  Relay(&mqttClient, 5, "ROLLET_UP", true),
  Relay(&mqttClient, 21, "ROLLET_DOWN", true)
};


ButtonHandler buttonHandlerLib(relays, RELAY_ARRAY_SIZE);

ButtoHandler h

#ifndef ButtonHandler_h
	#define ButtonHandler_h

  #include <Arduino.h>
  #include <Relay.h>

	class ButtonHandler
	{
		public:
		  ButtonHandler(Relay *relays, int arraySize);
		  void handle(String topic, String mqttCmmand);

		private:
		  Relay *relays;
		  int arraySize;
		  bool isButtonTopic(String topic);
                 void processCommand(String mqttCommand);
                 bool isMatch(String mqttCommand, String relayCommand);
	};

#endif

ButtonHandler cpp

#include "ButtonHandler.h"

ButtonHandler::ButtonHandler(Relay *relaysArg, int arraySizeArg) : relays(relaysArg), arraySize(arraySizeArg) {}

void ButtonHandler::handle(String topic, String mqttCommand)
{
  if (isButtonTopic(topic))
  {
    processCommand(mqttCommand);
  }
}

bool ButtonHandler::isButtonTopic(String topic)
{
  return topic.equals("/button");
}

void ButtonHandler::processCommand(String mqttCommand)
{
  for (int i=0; i < arraySize; i++)
  {
    String relayCommand = relays[i].getCommand();
    Relay relay = relays[i];

    if (isMatch(mqttCommand, relayCommand))
    {
       if (mqttCommand.indexOf("_SHORT") >=0)
       {
         relay.setAutoDisableTime(2000);
         //THIS DO NOT WORK - OBJECT USES STILL DEFAULT VALUE
         //SIMILAR CODE WORKS WHEN IS PLACED IN MAIN SKETCH

       }
       else if (mqttCommand.indexOf("_HOLD") >=0)
       {
          relay.setAutoDisableTime(30000);
          //THIS DO NOT WORK - OBJECT USES STILL DEFAULT VALUE
          //SIMILAR CODE WORKS WHEN IS PLACED IN MAIN SKETCH
       }

       relay.changeState() ;
    }

  }
}

bool ButtonHandler::isMatch(String mqttCommand, String relayCommand)
{
  return mqttCommand.startsWith(relayCommand);
}
    String relayCommand = relays[i].getCommand();
    Relay relay = relays[i];

relays is an array of pointers. You can't use . notation with pointers. You can't store a pointer in a object.

so what I can to make it work
this also do not work

void ButtonHandler::processCommand(String mqttCommand)
{
  for (int i=0; i < arraySize; i++)
  {
    String relayCommand = relays[i]->getCommand();

    if (isMatch(mqttCommand, relayCommand))
    {
       if (mqttCommand.indexOf("_SHORT") >=0)
       {
         relays[i]->setAutoDisableTime(2000);
       }
       else if (mqttCommand.indexOf("_HOLD") >=0)
       {
          relays[i]->setAutoDisableTime(30000);
       }

       relays[i]->changeState() ;
    }
  }
}

error: base operand of ‘->’ has non-pointer type ‘Relay’
String relayCommand = relays*->getCommand();*

relays is an array of pointers.

Sorry. That was wrong. relays is a pointer to an array. Though, why, I can't imagine.

What was the problem before you made that last change?

Why is relays not an array of pointers?

oqibidipo:
It does work, new returns a pointer.

So it does. My mistake.

I tried as array also:

#define RELAY_ARRAY_SIZE 2
Relay relays[RELAY_ARRAY_SIZE] = 
{ 
  Relay(&mqttClient, 5, "ROLETY_GORA", true),
  Relay(&mqttClient, 21, "ROLETY_DOL", true)
};


ButtonHandler buttonHandlerLib(relays, RELAY_ARRAY_SIZE);

ButtonHandler

lass ButtonHandler
	{
		public:
		  ButtonHandler(Relay relays[], int arraySize);
		  void handle(String topic, String mqttCmmand);

		private:
		  Relay relays[];
		  int arraySize;
		  bool isButtonTopic(String topic);
      void processCommand(String mqttCommand);
      bool isMatch(String mqttCommand, String relayCommand);
	};

cpp
ButtonHandler::ButtonHandler(Relay relaysArg[], int arraySizeArg) : relays(relaysArg), arraySize(arraySizeArg[]) {}

Error:
home/../Documents/Apps/arduino-1.6.5-r5/libraries/ButtonHandler/ButtonHandler.cpp: In constructor 'ButtonHandler::ButtonHandler(Relay*, int)':
/home/../Documents/Apps/arduino-1.6.5-r5/libraries/ButtonHandler/ButtonHandler.cpp:3:111: error: expected primary-expression before ']' token
ButtonHandler::ButtonHandler(Relay relaysArg, int arraySizeArg) : relays(relaysArg), arraySize(arraySizeArg) {}
^
/home/../Documents/Apps/arduino-1.6.5-r5/libraries/ButtonHandler/ButtonHandler.cpp:3:112: error: invalid initializer for array member 'Relay ButtonHandler::relays [0]'
ButtonHandler::ButtonHandler(Relay relaysArg, int arraySizeArg) : relays(relaysArg), arraySize(arraySizeArg) {}

I have a button class named iobutton and the following use of pointers works for me.

This part in globals:

iobutton  turnoff( 4, 20 ); // using jumpers for buttons = dirty buttons
iobutton  turnon( 5, 20 );
iobutton  goslower( 6, 20 );
iobutton  gofaster( 7, 20 );
iobutton  *buttons[ 4 ] =
{
  &turnoff, &turnon, &goslower, &gofaster
};

This part in setup()

  for ( byte i = 0; i < 4; i++ )
  {
    buttons[ i ]->startButton();
  }

And this part in loop()

  buttonRead = buttons[ buttonIdx ]->runButton( ); // only running 1 button per loop

BTW, it’s even more “fun” when the array (const data array only) is in PROGMEM.

For me it also work WHEN I use array with pointers in main sketch.

Issue is when I'm trying to move out code responsible for array iteration ( + actions) into external class as an class parameter.