Assigning Object To List

Hello,

I’m having issues with some of my code, and I was hoping someone would be able to point me in the right direction. The code can be found on Github, but I’ll post a summary of it here.

I have a RainDrop class whose header is defined as follows:

#ifndef RAINDROP_H
#define RAINDROP_H

class RainDrop {
  private:
    const int spriteWidth;
    const int spriteHeight;
    const int minSpawnPositionX;
    const int maxSpawnPositionX;
    const int minSpawnPositionY;
    const int maxSpawnPositionY;
    const int dropSpeed;
    const unsigned char sprite1[] PROGMEM;
    const unsigned char sprite2[] PROGMEM;
    
  public:
    int PosX;
    int PosY;
  
    //Initialize with random position
    RainDrop();
    //Update the RainDrop's position
    void Update();
    //Draw the RainDrop to the screen
    void Draw(Arduboy2 arduboy);
};
#endif

In my main project file, I define a list of this RainDrop class using

RainDrop drops[dropCount] = {};

and I have a method which initializes the RainDrops in the list like so:

void initDrops() {
    for (int i = 0; i < dropCount; i++) {
        drops[i] = new RainDrop();
    }
}

When I try to compile the code, the compiler gives me the following errors:

Arduino: 1.8.2 (Windows 10), Board: "Arduino Leonardo"
C:\Users\mmcgivern\Documents\Arduino\Rain\Rain.ino: In function 'void initDrops()':
Rain:20: error: no match for 'operator=' (operand types are 'RainDrop' and 'RainDrop*')
         drops[i] = new RainDrop();
                  ^
C:\Users\mmcgivern\Documents\Arduino\Rain\Rain.ino:20:18: note: candidates are:
In file included from C:\Users\mmcgivern\Documents\Arduino\Rain\Rain.ino:2:0:
sketch\RainDrop.h:4:7: note: RainDrop& RainDrop::operator=(const RainDrop&) <deleted>
 class RainDrop {
       ^
sketch\RainDrop.h:4:7: note:   no known conversion for argument 1 from 'RainDrop*' to 'const RainDrop&'
sketch\RainDrop.h:4:7: note: RainDrop& RainDrop::operator=(RainDrop&&) <deleted>
sketch\RainDrop.h:4:7: note:   no known conversion for argument 1 from 'RainDrop*' to 'RainDrop&&'
exit status 1
no match for 'operator=' (operand types are 'RainDrop' and 'RainDrop*')

I’ve tried just using the address-of and dereference operators in various places, but I haven’t been able to figure it out.
Any pointers would be highly appreciated.

Edit:
I managed to solve the problem on my own finally. I simply had to change the drops array to be of type *RainDrop.
Sorry to bug you guys with the pointless thread.

2 Likes

You haven’t fixed the problem, you’ve made a new one (if you’ll pardon the pun).

The specific problem is that new returns a pointer to an object. But this is the symptom of a deeper problem:

In normal circumstances new dynamically allocates some memory for your object in an area of memory referred to as the heap.
But Arduino doesn’t support new because Arduino boards don’t generally have enough memory for dynamic memory allocation to be useful.

(Dynamic memory allocation is a vast topic that you don’t need to know about if you’re just programming for Arduino and aren’t yet planning to move on to other things. If you would like to know more I will try to explain it, but it’s not necessary at this stage.)

The solution is to simply remove the word new.
Then your code becomes:

void initDrops() {
    for (int i = 0; i < dropCount; i++) {
        drops[i] = RainDrop();
    }
}

RainDrop() is now calling the default constructor of the RainDrop class, which creates a RainDrop object, which is then copied into drops[i]. (This copy may be elided by the compiler, meaning the drops are constructed directly into the array.)

I’ve updated the code based on your feedback.
Thanks for the help.
It’s been about 3 years since I last played with C++, so I’m a little rusty.

It’s understandable since new is used a lot in older C++ code and thus most tutorials mention it. Plus the wide use of new in C# and Java (where it has a different meaning) has spread into C++ slightly.

C++ has changed a lot in the last 7 years and it’s going to change again in 2020 (although nowhere near as drastically as 2011). Nowadays the consensus is to avoid pointers where possible, but as the Arduboy is an embedded system there are slightly different considerations involved so pointers are more acceptable, but you still have to be careful with how you’re using them.

Looking at your github page you’ve fixed some of the other issues I was going to mention, but I’m going to make some more suggestions.

Firstly I would advise against using int unless necessary because int on Arduino is 16-bit, and the CPU registers are only 8-bit, so if you aren’t exceeding the range of 0…255 or -128…127 then you’d be better off using char (or better yet, int8_t and uint8_t). Using a smaller type will give you more progmem because you don’t need as many CPU instructions. Using unsigned types when you don’t need negative values has the same effect.

Secondly, in Draw(Arduboy2 arduboy) you are passing arduboy by value, which means the entire arduboy object is copied, which can be costly. If you use a reference instead, like so Draw(Arduboy2 & arduboy), you won’t need to do any copying, the compiler will know how best to handle the reference (sometimes it’s by secretly using pointers, sometimes it has other tricks).

Lastly I don’t think making the raindrop’s position random in the default constructor is a good idea. For one thing, the default constructor is implicitly called for every item in the array at the start of the program so you end up calling it twice when you do initDrops (though the first time will be before initRandomSeed is called, making it even more redundant). There are other reasons, but those are more about what’s conventional/best practise rather than something that’s actively affecting your program’s performance/memory use.

1 Like