For this simple example, you don't need new. If you have some "real work" that needs it, well, you are out of luck with avr-gcc. unless you write your own new operator (using malloc or some such thing). That might not be as simple as some people think. Also, it's just too easy to create C++ code that requires lots and lots of storage in ways that are not always obvious. Maybe that's why embedded programmers sometimes try to get along without dynamic memory allocation all together. (I wouldn't try implement my own new operator, but that's just me: I'm funny that way.)
Anyhow, maybe you can figure out how implement your stuff without needing it by trying something like the following. (See Footnote.)
// After debugging, you can put the class definition
// and implementation in separate .h and .cpp library
// files.
//
// davekw7x
//
// Class Definition
//
class MyClass {
public:
MyClass();
MyClass(int var);
int getVar() const;
void putVar(int val);
private:
int _var;
};
//
// Class implementation
//
// Default constructor sets _var to zero
MyClass::MyClass():_var(0) {}
// Constructor with initializef for _var
MyClass::MyClass(int var):_var(var){}
// Getter function
int MyClass::getVar() const {return _var;}
// Putter function
void MyClass::putVar(int val) {_var = val;}
//
// The Maybe create your own main() instead of this sketch
//
const int ROWS = 3;
MyClass arr[ROWS]; // An array of MyClass objects using default constructor
//
// Initialize the objects in setup()
//
void setup()
{
Serial.begin(9600);
for (int i = 0; i < ROWS; i++) {
arr[i].putVar(11*(i+1));
}
}
//
// Use the objects in loop()
//
void loop()
{
for (int i = 0; i < ROWS; i++) {
Serial.print("arr[");
Serial.print(i); Serial.print("].getVar() = ");
Serial.println(arr[i].getVar());
}
Serial.println();
delay(10000);
}
Since I wanted to test it with a simple Arduino sketch and the Arduino setup() function doesn't take parameters, I had to make the array a global (file-scope, actually) variable. That's one of those irritating little things that drives Big-Time C++ programmers nuts. Of course to do it like "real" C++ programmers would probably do it, you could put the array initialization code (or a function call to do the deed) at the begging of loop(), and then follow that by an infinite loop so that loop() never returns to Arduino's main() function. Then the array could be a local variable inside of Arduino's loop() function.
"Real" C++ programmers' irritation that is often caused by being faced with limited resources, like not enough RAM in these embedded systems to allow them to use oodles and oodles of dynamically allocated memory without worrying about code efficiency, is one of the other things that explains a lot.
Regards.
Dave
Footnote:
This is a very simple example. It won't work if ROWS has to be a variable (not known at compile time). You have to evaluate your design to see whether something like my example would be practical in light of your requirements.
No. What you are doing is allocating (using the wrong function) space for an instance of MyClass, but you are not actually creating an instance of MyClass.
A sparse array is one that has only a few values actually stored in it. The array you have defined is then filled completely. Hardly the definition of sparse.
p now points to a block of space large enough to hold an instance of myClass. It does NOT point to an instance of myClass. [/quote] The code works. I made sure before I posted it.
I know what malloc does. It returns a pointer to a block of memory. It does nothing to initialize that memory. The type cast of the return value is required because malloc is just returning a pointer (of type void) to the first memory location allocated.
I suppose that it is working similar to a dynamically allocated struct (which I'm sure that you have heard about- If not, look for some examples on linked lists).
These work in a similar way: The malloc statement is used, and you can write to any of the elements using the pointer the malloc returned.
@InvalidApple:
I think you're misunderstanding the difference between a class (or object) and a struct.
As PaulS pointed out, malloc'ing some memory and casting the pointer to it does not a class instantiate.
If you doubt me, try calling one of the class methods.
@Groove
That's the thing we are having the discussion about. He says that he did run the sketch, which does call the instance's methods, and that it worked.
Personally, I have a Java background, but I'm pretty familiar with C's malloc.
I initially avoided malloc because many C++ "tutorials" suggest staying away from malloc as it is often a source for memory leaks. However, if it's the only way to truly dynamically allocate memory, it shouldn't be an issue.
After digesting InvalidApple's code and the responses generated I have concluded that malloc must call the default constructor for MyClass (without the int parameter).
#define ROWS 3
class MyClass {
int _var;
public:
MyClass() {
_var = 0;
};
MyClass(int a) {
_var = a;
};
void setVar(int a) {
_var = a;
}
int getVar() {
return _var;
};
};
MyClass *arr;
void setup() {
Serial.begin(9600);
arr = (MyClass *) malloc(sizeof(MyClass) * ROWS);
for(int i = 0; i < ROWS; i++)
arr[i].setVar(i + 1);
for(int i = 0; i < ROWS; i++)
Serial.print(arr[i].getVar());
//Should return '1 2 3'
}
void loop() {}
Currently I don't have an Arduino to test this on, but I'm pretty sure this works. Multidimensional arrays would just require more 'for' loops.
Now for the real question:
Are objects extremely memory intensive (for an Arduino)? I've created a simple pixel class that lets me easily set the color of an RGB LED and I plan to create up to 64 of these 'Pixel' objects. Are there more efficient structures for this type of application?