"->" vs "." to access class members?

I have a couple of questions regarding classes.

Why are instances of a class often created with the "new" keyword, creating a pointer to that instance, and then non-pointer members of that class instance dereferenced using "->" in most Arduino sketches that I see?

Let's pretend we have a class.

int totalSwitches = 0;

class Switch {
  public:
    bool isOn = false;
    Switch() {totalSwitches++;}
    void flip() {isOn = !isOn;}
};

For the most part, I see this:

Switch *switchA = new Switch;
switchA->flip();
if (switchA->isOn) {Serial.println("Switch A is on!");}

Is there a reason to use the above code instead of the following?

Switch switchA;
switchA.flip();
if (switchA.isOn) {Serial.println("Switch A is on!");}

And one final question. In a struct (not a struct class, but a struct as in a structure with no member functions) I can create several instances at the outset as an array. Can I do the same with a class? For example:

int totalSwitches = 0;

class Switch {
  public:
    bool isOn = false;
    Switch() {totalSwitches++;}
    void flip() {isOn = !isOn;}
}switches[3];

And then access the instances of that class like this?

switches[2].flip();
if (switches[2].isOn) {Serial.println("Switch 3 is on!");}

The benefit of using "Class *c = new Class()" and access members with "c->what()" is that the memory occupied by that object can be released with "delete c" - if you make a static allocation "Class c" and access it with "c.what()", the memory it occupies cannot be released.

Yes you can declare arrays of structs or classes. In fact, the only difference between "class" and "struct" is that in a struct the members (variables) are public by default whereas they are private in a class.

NOTE: Arduino has a very crude memory management. Whenever it is possible, use static declarations. You should not use dynamic memory (allocate and release) since it may cause memory fragmentation leading to corruption and eventually a "crash" where the sketch/device becomes defunct until it is being reset.

‘->’ and ‘.’ notation are carry-overs from ‘C’ structs and pointers. Use in C++ parallels this.

‘new’ creates the object on the heap dynamically at run time and returns a pointer. Similar idea to ‘malloc()’.

‘Switch switchA;’ creates the object as a variable either in static / global space or on the stack (guess you could say this case is dynamic too) depending on where the declaration / definition is placed.

‘Switch switches[3];’ creates an array of 3 Switch objects.

‘Switch *switches = new Switch[3]’ dynamically creates an array of three switch objects and returns a pointer to the first one.

Edit:
Fixed dynamic array example.

jwllorens:
Why are instances of a class often created with the "new" keyword, creating a pointer to that instance, and then non-pointer members of that class instance dereferenced using "->" in most Arduino sketches that I see?

Are you asking why you need to use the '->' operator, or are you asking why the class is dynamically instantiated?

jwllorens:
Is there a reason to use the above code instead of the following?

Oh. Well, the usual reason for using dynamic allocation of objects is when you only know at run-time how many objects you will need or how they will be initialised. Or if that changes over the lifetime of the sketch (for whatever reason).

For instance, if a sketch has to ask a user how many thingies they want to work with, you can do this either by statically allocating as many thingies as any user is ever going to want and only using some of them, or you can do it by dynamically allocating them with new at the time when you find out how many you will need.

Another example might be some sort of model train system where a person might put carriages down on the track and remove them, and the sketch detects this and uses object instances to manage carriages and trains of carriages as time goes on.

jwllorens:
And one final question. In a struct (not a struct class, but a struct as in a structure with no member functions) I can create several instances at the outset as an array. Can I do the same with a class?

Yes. And you wouldn't have needed to ask this question if you had just written a little test sketch to try it out.

jwllorens:
For the most part, I see this:

I almost never see code like that in the Arduino world.

I appreciate the replies. The reason I ask this is because I came across the following reply in another thread somewhere discussing some code on an Arduino which seemed consistent with several example sketches I have been looking at.

Finally you have to change the direct calls (e.g .SwitchStateChanged()) to indirect (so ->SwitchStateChanged()). This is the standard way to handle objects.

In light of these replies, it would seem that the above quote was from someone that was offering more general programming advice, but specifically for most AVR applications it is sufficient to statically instantiate a class due to memory allocation constraints.

However, is there any drawback to using "new" to instantiate an object when setting up the environment (basically, just once within setup()) and then leaving it be and never deleting or creating new instances of the class after that?

Yes. And you wouldn't have needed to ask this question if you had just written a little test sketch to try it out.

Or, I could throw an additional, somewhat-related, simple yes-or-no question behind the primary topic question and get a quick, easy, yes-or-no answer from friendly and helpful people such as yourself that were kind enough to reply.

Much appreciated.

jwllorens:
However, is there any drawback to using "new" to instantiate an object when setting up the environment (basically, just once within setup()) and then leaving it be and never deleting or creating new instances of the class after that?

I don't really think so (others probably have different opinions). But, no real advantage either. Make sure the pointer that receives the result of 'new' is global. Otherwise, it will go out of scope when setup() exits. This will "orphan" the object that you just created with new. You won't be able to access it anywhere.

pert:
I almost never see code like that in the Arduino world.

I am about 5 days into learning how to program, and I am trying to run a bunch of steppers asynchronously off of a Mega2560. I came across this while trying to teach myself how to program over the past 5 days:

I couldn't figure out what the point of bothering with the pointers was, and why the Motor objects weren't just created with "Motor m1;". I found several other examples like this, and then came across this too:

gfvalvo:
I don't really think so (others probably have different opinions). But, no real advantage either. Make sure the pointer that receives the result of 'new' is global. Otherwise, it will go out of scope when setup() exits. This will "orphan" the object that you just created with new. You won't be able to access it anywhere.

When it goes out of scope, wont the default destructor be called?

jwllorens:
When it goes out of scope, wont the default destructor be called?

For statically allocated objects the default destructor is called when they go out of scope. Dynamically allocated objects remains in memory for no reason - even if out of scope. Another reason not to use dynamic allocation unless anything else is impossible :slight_smile:

jwllorens:
When it goes out of scope, wont the default destructor be called?

Nope!!!
It's the pointer that goes out of scope, not the object that you created dynamically. If you want to destruct the object, you must use 'delete' before you loose the pointer.

This is exactly analogous to the situation in C. You must 'free()' the memory that you 'malloc()' before you loose the pointer.