1

How can I declare an empty global array, to be initialized in setup?

What I would like to do is this:

#include <ResponsiveAnalogRead.h>

const size_t ANALOG_SIZE = 3;
const int ANALOG_PINS[ANALOG_SIZE] = {A0,A1,A2};
ResponsiveAnalogRead analog_reads[ANALOG_SIZE];


void setup() {
  for(size_t i=0; i<ANALOG_SIZE; i++){
    analog_reads[i]=ResponsiveAnalogRead(ANALOG_PINS[i], true, 0.01);
  }
}

But the error I get is:

sketch_may29c:5: error: no matching function for call to 'ResponsiveAnalogRead::ResponsiveAnalogRead()'
 ResponsiveAnalogRead analog_reads[ANALOG_SIZE];

                                              ^

Is it impossible to declare an empty array of a given size?

  • 1
    did you try the example sketch that came with the library? – jsotola May 29 '18 at 20:46
  • @jsotola yes, that compiles just fine, but that uses only one ResponsiveAnalogRead object. github.com/dxinteractive/ResponsiveAnalogRead also shows how to use multiple, but initializes them globally, not in setup, I want to loop over an array of pin-numbers to initialize multiple of them. – RedPixel May 29 '18 at 20:48
1

As Craig wrote, the declaration of an class typed array will call the default constructor of the class, which is the one without any arguments. The class, that you use, does not provide a default constructor, since it needs it's parameters. You cannot do it this way.

But you can use dynamic allocation. In global scope only declare an array of pointers to ResponsiveAnalogRead objects:

ResponsiveAnalogRead *analog_reads[ANALOG_SIZE];

This array only holds pointers, that can point to ResponsiveAnalogRead objects. The objects themselves are not created yet. In setup() you can then create the objects dynamically with the new statement:

analog_reads[0] = new ResonsiveAnalogRead( input_parameters);

(Of course you have to replace input_parameters with all parameters, that the constructor needs). To call a member of the object, you can dereference it like this:

analog_reads[0]->member_function();

If you don't know about pointers yet, you should google for a tutorial (there are plenty), so that you understand the principle behind them.

Important note: Dynamic allocations of memory geht written to the heap in RAM. Since the Arduino (especially the Atmega based ones) has only very limited RAM, dynamic allocations have to be handled with great care. You should not create and delete data often in your program, since this would make swiss cheese out of your heap. But allocating the memory only once in your program and never deleting it, will not be a problem, as long as you don't try to allocate too much memory.

  • Makes sense! I have some experience in C, so I do know pointers :) Thanks for elaborating. – RedPixel May 30 '18 at 6:38
3

Craig already explained the reason of the error is the lack of a default constructor, and chrisl suggested a reasonable alternative. I would like to suggest two other alternatives.

Static initialization

You state that you want to do the initialization in setup(), but you don't explain why you want that. I will guess that what you really want is to have all those objects in array. The library page provides this example showing how to statically initialize multiple instances:

ResponsiveAnalogRead analogOne(A1, true);
ResponsiveAnalogRead analogTwo(A2, true);

The problem with this example is that you don't have an array, so you cannot loop through the instances. This problem, however, can be easily fixed:

const size_t ANALOG_SIZE = 3;
ResponsiveAnalogRead analog_reads[ANALOG_SIZE] = {
    ResponsiveAnalogRead(A0, true),
    ResponsiveAnalogRead(A1, true),
    ResponsiveAnalogRead(A2, true)
};

Note that you don't need the ANALOG_PINS array anymore. And you don't need to pass 0.01 as the last argument to the constructor, as this is the default value anyway. This would be my preferred solution: it is simple enough and doesn't increase the number of lines of code.

Patching the library

If you really want to initialize the array in setup(), then you can patch the file ResponsiveAnalogRead.h from the library:

  1. Add default values to all the parameters of the constructor. For example:
ResponsiveAnalogRead(int pin=0, bool sleepEnable=0, float snapMultiplier=0.01);
  1. Add a method for setting the pin after initialization:
void setPin(int newPin) { pin = newPin; pinMode(pin, INPUT); }

The first change will enable you to compile your code as-is. The second change will allow you to update the objects in setup() rather than overwriting them (which I don't find very elegant):

for (size_t i = 0; i < ANALOG_SIZE; i++) {
    analog_reads[i].setPin(ANALOG_PINS[i]);
    analog_reads[i].enableSleep();
}

Note that using the default constructor now has the side effect of setting pin 0 to input. This should not be a big deal, as the constructor is called before setup(), and all the IO pins are inputs at this point. If you want nevertheless to void that side effect, then set the default pin to -1, and patch the constructor to only configure the pin if it's not -1.

Patching the library creates a maintenance burden though: you will have to reapply the patch each time the library is updated. This may not be that bad if you know how to git rebase or git merge, but ideally you would want to get a pull request accepted by the original maintainer.

Edit: Before patching the library, consider weighting in this issue and using this fork.

Update: A pull request addressing this issue has been accepted. As of version 1.2.0, the class has now a default “do nothing” constructor.

  • Thanks for an even more elaborate answer! By the way, the reason I want to initialize in setup() is because I want to multiplex these analog pins to 16 channels. I want each multiplexed channel to have its own ResponsiveAnalogRead object. That also means I do not want to get rid of the ANALOG_PINS array, because I want to loop over that 16 times :) I considered patching the library after @Craig 's answer, but I have no C++ experience. Thanks for suggesting the issue and the fork, but I've gone with the solution offered by @chrisl already. – RedPixel May 30 '18 at 18:48
1

When you declare an array it will call the default constructor for the type. ResponsiveAnalogRead does not have a default constructor so it cannot initialize the entries in the array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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