Set size of member array at runtime

TL;DR
I have a class that contains an array. Sometimes I want to instantiate an object of that class in which the array has 100 members. Other times, I only want 10. The object is instantiated immediately when the program runs (at compile time, maybe?) and lasts the length the the program. How do to?


I realize I'm dipping my toes into contentious waters here. I've studied related posts (e.g. https://forum.arduino.cc/t/how-to-create-and-free-dynamic-arrays-with-arduino/934662. It's not clear to me how those answers apply to my problem.

I have a RollingAverage class. Clearly, this class includes an array of samples to be averaged. Currently, this is hard coded to 100. An object can be initialized to use whatever portion of the total array is needed. The values in the array can be any type (it's a class template). This works well under extensive testing.

Now, the class is useful enough that I've begun using objects of it all over the place. Problem is, several of these uses need a rolling average of unsigned long, and only really need 10 samples for the rolling average.

So my problem is this: I simply want to be able to set the size of the array upon construction (probably as a parameter passed to the constructor). All of these objects are members of objects that are created on runtime. They will exists for the life of the program. I'm unclear whether that even counts as "dynamic memory allocation".

I am aware of solutions involving creating an array in outer class or setup() loop and passing it into the constructor as a reference or something....I don't really like that because it goes against encapsulation and could result in side-effects if the outer code goes messing with that array.

Please let me know if seeing any source code would be helpful.

IIRC sizeof(array) / 2, since the array is actually pointers, this works no matter what the array is made of.

Isn't it platform-dependent?

Are you sure? Pointer size is 2 bytes ALWAYS?

I'm not sure I understand. sizeof returns the size of the current array, yes? What I'm trying to do is set the size of the array in the object's constructor.

IOW I'm not trying to determine the size of the array in the sense of finding out what it is, but rather in the sense of creating it with a given size that is determined by a parameter passed to the object's constructor.

Do you mean this? If not then post your code and explain the problem better.

template<class T>
class MyClass {
  public:
    MyClass(size_t arraySize) {
      arrayPointer = new T[arraySize];
    }

    ~MyClass() {
      delete[] arrayPointer;
    }

  private:
    T *arrayPointer;
};


MyClass<uint32_t> object1(100);
MyClass<char> object2(50);

void setup() {
}

void loop() {
}
1 Like

Ah, that's brilliant. As a noob I would never have thought of that. I would then use arrayPointer the same way as I would use an array normally? e.g. arraypointer[3] = 5; sizeof(arrayPointer); etc.

Or do I have to dereference it each time?

Also, I presume I can name it something normal like sensorDataArray?

Thanks for being patient with me.

Both of these will work:

   arraypointer[index] = something;
   *(arraypointer + index) = something;

NO!
sizeof(arrayPointer) is 2 or 4 depending on the platform. You already know what the size is since you created the array. Just save that number in a variable.

Name it whatever you like.

1 Like

Another option would be std::array. You can initialize it runtime. And even add members later on (highly not recommended on mcu).

NO!
sizeof(arrayPointer) is 2 or 4 depending on the platform.

Right, sizeof would just be returning the size of the pointer, I get it.

Thanks again. I think this little example also gives me some insight into using pointers (eventually). I'll let you know how my testing goes.

I'm pretty sure the size of a std::array is fixed once it's created. A std::vector is dynamically resizeable.

You are right, I came here to edit my post, but I am late...
So: std::vector could do the job...

I don't need the size of the array to be variable once created.
I just sometimes need a rolling average with 1000 samples; sometimes I only need 10. Want to define that at compile time. Solution from @gfvalvo works.

Btw, @gfvalvo, it took me some debugging to figure out that the array that's formed has values in the cells already. I have to do a loop to initialize each cell to zero.

If you do not want to spend 2000 bytes, you could also use something like:

uint32_t averageproxyTimes1024, averageProxy;
//In setup:
averageproxyTimes1024 = analogRead(A0) * (1<<10);

//In loop:
averageproxyTimes1024 = (averageproxyTimes1024*1023 + analogRead(A0)*(1<<10) + 512)/1024;
averageproxy = averageproxyTimes1024/1024;

This will also be very fast using integer math and bitshifts for division.

1 Like

I don't understand how that works.

Of course there must be some values there, memory can't be "empty". When allocated dynamically, an array of POD (plain old data) will initially contain whatever values happened to be in those memory locations before they were allocated to the array. Same as for a local variable in a function.

Exponential Moving Average.

1 Like

When allocated dynamically, an array of POD (plain old data) will initially contain whatever values happened to be in those memory locations before they were allocated to the array.

That makes sense. The values do get zeroed out when you declare an array in the "usual" way, however? i.e. int anArray[50]

Is there a more elegant way to zero out a dynamically allocated POD than a for next loop?

Exponential Moving Average

Ok, I was studying this, and thought I might understand it, and then I saw that the original poster had edited his/her suggestion and I'm lost again lol.

Is this using "Basic exponential smoothing" ? According to the wiki that's basically (sorry don't know how to do subtext here) St = S(t-1) + A(Xt - S(t-1)), where St is the current "average", Xt is the current data point being included in the average, and A is a smoothing factor that is 0 < A < 1.

Are you using 1/1024 as the smoothing factor A? Using the formula from the wiki, I don't understand where the extra multiplications, bitshifts and addidtions are coming from here.

averageproxyTimes1024 = (averageproxyTimes10241023 + analogRead(A0)(1<<10) + 512)/1024;

Also if the smoothing factor is 1/1024, why is it being included again here:

averageproxy = averageproxyTimes1024/1024;

Hello, thank you for this.
I studied the wiki on Exponential Moving Average that gfvalvo posted, but I'm still totally lost here.

Would you be willing to help me understand what is going on here?

What don't you understand?

Every cycle, you add a fixed fraction of the latest sample, to a running total minus that same fraction.
The smaller the fraction, the more sluggish the response of the filter.

std::array would work, since I don't need to dynamically resize it.
How does that work with the context I have though, where I need to set the size in the constructor of the object that has the array as a member?

Would it still be like gfvalvo's example, but with a different syntax for declaring the array?:

template<class T>
class MyClass {
  public:
    MyClass(size_t arraySize) {
      arrayPointer = new array<T,arraySize>;
    }

    ~MyClass() {
      delete[] arrayPointer;
    }

  private:
    T *arrayPointer;
};


MyClass<uint32_t> object1(100);
MyClass<char> object2(50);

void setup() {
}

void loop() {
}