I'm trying to pass an array to a C++ class, in order the make the changes to the array objects visible outside the class. But it is not working. The changes to the Motor
objects are lost after every call.
It's an Arduino project using the ESPAsyncWebServer. Not sure whether this matters.
See the project on github for full source code.
In the setup()
method I'm defining the array and pass it into the the web-server:
void setup()
{
std::array<Motor, NOF_MOTORS> motorArray = {
Motor(1, 0, 1, DEFAULT_PWM),
Motor(2, 2, 3, DEFAULT_PWM)};
server.addHandler(new RequestHander(motorArray));
}
The RequestHandler
constructor is taking the array by reference:
class RequestHander : public AsyncWebHandler
{
public:
RequestHander(std::array<Motor, NOF_MOTORS> &motorArray) : motorArray_(motorArray) {}
private:
std::array<Motor, NOF_MOTORS> motorArray_;
}
Any ideas why the Motor objects are not changed? To me it feels as if they were some how passed by value.
Yes, you are passing the std::array
by reference into the RequestHander()
constructor, but you are then making a copy of the array (and thus a copy of the Motor
objects) when initializing the motorArray_
member, which is not a reference. So, any subsequent changes you make to the motorArray_
elements are not reflected back to the original array.
You could change the motorArray_
member into a reference, eg:
std::array<Motor, NOF_MOTORS>& motorArray_;
But this would be very dangerous in the code you have shown, because the original std::array
is a local variable of setup()
and will go out of scope when setup()
exits, leaving motorArray_
dangling.
So, you have some options:
change RequestHander
to take ownership of the original std::array
before it goes out of scope:
#include <array>
#include <memory>
void setup()
{
auto motorArray = std::make_unique<std::array<Motor, NOF_MOTORS>>();
(*motorArray)[0] = Motor(1, 0, 1, DEFAULT_PWM);
(*motorArray)[1] = Motor(2, 2, 3, DEFAULT_PWM);
server.addHandler(new RequestHander(std::move(motorArray)));
}
#include <array>
#include <memory>
class RequestHander : public AsyncWebHandler
{
public:
RequestHander(std::unique_ptr<std::array<Motor, NOF_MOTORS>> motorArray) : motorArray_(std::move(motorArray)) {}
private:
std::unique_ptr<std::array<Motor, NOF_MOTORS>> motorArray_;
};
Alternatively, if you don't strictly need the std::array
:
#include <memory>
void setup()
{
auto motorArray = std::make_unique<Motor[]>(NOF_MOTORS);
motorArray[0] = Motor(1, 0, 1, DEFAULT_PWM);
motorArray[1] = Motor(2, 2, 3, DEFAULT_PWM);
server.addHandler(new RequestHander(std::move(motorArray)));
}
#include <memory>
class RequestHander : public AsyncWebHandler
{
public:
RequestHander(std::unique_ptr<Motor[]> motorArray) : motorArray_(std::move(motorArray)) {}
private:
std::unique_ptr<Motor[]> motorArray_;
};
change the std::array
itself to hold pointers to Motor
objects, but pass around the array itself by reference and move the pointers as needed:
#include <array>
#include <memory>
void setup()
{
std::array<std::unique_ptr<Motor>, NOF_MOTORS> motorArray = {
std::make_unique<Motor>(1, 0, 1, DEFAULT_PWM),
std::make_unique<Motor>(2, 2, 3, DEFAULT_PWM)
};
server.addHandler(new RequestHander(std::move(motorArray)));
}
#include <array>
#include <memory>
#include <algorithm>
class RequestHander : public AsyncWebHandler
{
public:
RequestHander(std::array<std::unique_ptr<Motor>, NOF_MOTORS> &&motorArray) {
std::move(motorArray.begin(), motorArray.end(), motorArray_.begin());
}
private:
std::array<std::unique_ptr<Motor>, NOF_MOTORS> motorArray_;
};