Reputation: 11
I ran into a little problem here, and I'm kind of stuck, tried googling it but couldn't find a solution that helped. Hopefully somebody here can help.
So I have this little class here. I'm trying to initialize Button members in a loop and push the created members to a vector named btns. I thought this way I can update the button members in a method by just looping through the btns vector and call each of the members update function. The button.update() function basically just sets a state to this point.
So far this works quite good, or at least every Button gets its correct init values. I run into the weird behaviour when I want to call the button.update() function. As I already mentioned, every button has a boolean member called "state" that gets initialized with the value false. For the test purpose, I tried to set the state of a button to true with the button.update() method. The problem is now, when I try to check if the update worked and read back the value of state, I only get back true if I call the button.update() method in the same scope as the read back. If I want to get the value of state later, it comes back as false, and I really can't understand or explain why.
This is the class I'm talking of:
#include <ucRP2040.hpp>
ucRP2040::ucRP2040(std::vector<u8_t> btns, std::vector<u8_t> leds)
{
for (u8_t pin : btns)
{
Button btn(pin);
// btns here is a std::vector<Button>
this->btns.push_back(btn);
}
}
void ucRP2040::update()
{
/*Input*/
for (Button btn : btns)
{
btn.update();
}
for (Button btn : btns)
{
// btn.update(); <- if I uncomment this line, state works
Serial.print(" state: ");
//only works if btn.update() was called in loop scope
Serial.println(btn.state); //gives back false
//This works correct
Serial.print("size: ");
Serial.print(btns.size());
Serial.print(" pin: ");
Serial.print(btn.pin);
}
// This does not work at all, gives back false
Serial.println(btn[0].state);
delay(500);
}
This is the Button class:
#include <Button.hpp>
Button::Button(u8_t pin) : pin{pin}, state{false}
{
}
void Button::update()
{
state = true;
}
This is my main:
#include <ucRP2040.hpp>
#include <Arduino.h>
// USER BUTTON abd LEDs
std::vector<u8_t> usrbtns = {13, 14, 15};
std::vector<u8_t> usrleds = {22, 23, 24, 25};
// INIT HW
ucRP2040 ucrp2040(usrbtns, usrleds);
void setup()
{
Serial.begin(9600);
}
void loop()
{
ucrp2040.update();
}
I tried to break it down and leave comments in the code, maybe this is more self-explanatory. Has anybody a clue what I'm doing wrong?
Upvotes: 1
Views: 49
Reputation: 118292
for (Button btn : btns)
This is range iteration by value. In the for
loop, the btn
object is a copy of each value in the btns
container.
btn.update();
// ...
void Button::update()
{
state = true;
}
This modifies the btn
object. And at the end of the loop, btn
gets destroyed. It disappears. It becomes no more. It ceases to exist. It starts pining for the fjords. It becomes an ex-Button
.
Instead, iteration by reference should be used in order to update each value in the array:
for (Button &btn : btns)
Now, btn
will be a reference to each value in the btns
container, iterating over it.
The other for
range iteration will likely need the same change. Even if it doesn't modify each Button
object this will likely optimize out an utterly useless copy of each Button
that happens when iterating by value.
This is no different than passing parameters to a function. As you know, parameters get passed by value, and each parameter in the function is a copy of the passed-in object; while a reference function parameter ends up passing by reference. Same thing.
Upvotes: 2