Defining the size of global array on library/class instance creation. Possible?

Im writing a library and I need an array (_arrayName) of a specifiable size to be global. So I need to allow setting the size of that array when you call an instance of the library.

#ifndef Thermal_h
#define Thermal_h

#include <WProgram.h>
#include <WConstants.h>

class Thermal{
  public:
    Thermal(size);

  private:
	int _arrayName[*]
};

#endif
#include <WProgram.h>
#include <WConstants.h>
#include "Thermal.h"

Thermal::Thermal(int size){
  //need way to set the size here	
  _arrayName[size];
}

Then just do this to set that
Thermal foo(3);

Is this doable?

Is this doable?

Yes, it is. If the environment were more expansive than the Arduino, STL’s vector<> would be the answer. So here’s a smaller version of that that I wrote. The code here is all the testing I’ve done, but there shouldn’t be any problems. Let me know if you have any.

One note of caution: to avoid relying on an implementation of new and delete, I’ve used malloc and free, so if you were to use anything other than a native type (int, etc.), such as a class, the array would be filled with uninitialized instances of that class (the constructor would not have been called.) I could use in-place new, but that would just be too obscure for this little thing. So stick to ints, bools, floats, etc.

template< typename T > class Array
{
public:
            Array( size_t size )       : size( size ), data( static_cast< T * >( malloc( sizeof( T ) * size ) ) ) {}
           ~Array()                    { if ( data ) free( data ); }
  T &       operator[]( size_t index ) { return *(data + index); }
  size_t    Size()                     { return size; }  

private:
            // copying not supported
            Array( const Array & rhs );
  Array & operator=( const Array & rhs );
  
  size_t    size;
  T *       data;
};

class SomeClassWithDataArray
{
public:
  SomeClassWithDataArray( size_t sizeOfDataArray )
    : dataArray( sizeOfDataArray )
    {
    }
    
  Array< int > dataArray;    
};


void setup()
{
  Serial.begin( 9600 );
  
  SomeClassWithDataArray instanceOfClass( 5 );

  for ( uint8_t index = 0; index != instanceOfClass.dataArray.Size(); ++index )
  {
    instanceOfClass.dataArray[ index ] = 2 * index;
  }
  
  for ( uint8_t index = instanceOfClass.dataArray.Size(); index != 0; --index )
  {
    Serial.println( instanceOfClass.dataArray[ index - 1 ], 10 );
  }  
}

void loop()
{
  
}

Kerthyn

You can use the STL vector class without too many problems.

http://www.gammon.com.au/forum/?id=11119

It is a slight pain in that you have to copy the STL files into your Arduino "include" folder, rather than your Libraries folder which would be more modular. However it works, and you only have to do that once. For a vector, it adds 1000 bytes or so to a sketch size, which isn't too bad considering you may have 32 Kb to play with on the Atmega328.

The code also includes new and delete operators, so you can have arrays of classes if you really need that.

For simple situations, Kerthyn's solution will no doubt be fine. I started doing something similar a while back in response to a similar question, but then found that the full STL library could be incorporated for modest overhead.

Kerthyn - the only major problem I see is that you are allocating the array in the constructor, which means that either you need to do a "new" anyway (so the constructor can be called dynamically) or you have the array declared statically (in which case its size is limited to compile-time), or in a function (as you did), but then it only lasts the lifetime of the function.

For example, how would you access instanceOfClass outside setup? Or if you move it to global scope, how do you make the number of items variable? Without doing that, you may as well use a static array.

The STL vector can grow dynamically (ie. you can keep adding to it at runtime) which may or may not be useful to you.

Nick -

the only major problem I see

That isn't a problem, major or otherwise; bildr's requirement was for intializing in the ctor:

Thermal::Thermal(int size){
  //need way to set the size here  
  _arrayName[size];

Had the requirement been for initializing subsequently, I would have had the ctor NULL the pointer and set size to 0, and added an initializer.

I don't like bringing in STL to the Arduino environment. I've used it for years (and Boost too,) and they work beautifully; but I don't like to use code that's written to assume that it's OK to use new and delete during normal use. I'd do it if I needed to, and would control how it was used, and things would be fine. But I wouldn't recommend it for somebody unfamiliar with STL.

Hmm, I thought this looked familiar, initializing the Thermal class in the constructor:

http://arduino.cc/forum/index.php/topic,69063.msg510551.html

I mention this because in that thread I suggested using new/delete, and bildr responded: “Perfect!”.

Now, using new/delete (or malloc/free) would be a way of allocating an array dynamically at runtime.

eg.

int * _arrayName;

Then in the constructor:

_arrayName = new int [size];

or:

_arrayName = (int *) malloc (sizeof (int) * size);

Now you have your dynamically-allocated array of ints.

And I'd be surprised if the resulting compiler output differed greatly with either approach.

I suggested the array template approach because I feel that it's better to push less experienced developers away from code that marches through a buffer; even if the underlying code amounts to the same thing, unless the data is received or will be sent somewhere as 'n bytes starting here,' I prefer to encourage them to think in terms of the slightly higher level constructs when writing code that deals with the elements.

:) This is for a different library. I just got lazy and used the same "thermal" class as the base for the question.

[quote author=Nick Gammon link=topic=69256.msg512704#msg512704 date=1313215383] Hmm, I thought this looked familiar, initializing the Thermal class in the constructor:

http://arduino.cc/forum/index.php/topic,69063.msg510551.html [/quote]

I had looked at doing it with vectors originally, but quickly found out it was not supported. Then looked at templating it, and I think I did something wrong because that didn't work other.

But I think this helps a lot. Thanks!