gator gator - 9 months ago 31
C++ Question

Difficulty with mutation involving classes

I have a class,

characterData
, and a list of this type:

class characterData {
private:
vector<vector<int> > pixelData;
int area;
public:
void setPix(vector<vector<int> > in) {
pixelData = in;
area = in.size() * in[0].size();
}
vector<vector<int> > getPix() {
return pixelData;
}
int getArea() {
return area;
}
};

list<characterData> listChars;


I'm trying to mutate
pixelData
in other methods, but keep running into issues. I have a method which does some function to
pixelData
:

void processHandler(list<characterData> &inList) {
while (!inList.empty()) {
normalize(inList.front().getPix());
inList.pop_front();
}
}

void normalize(vector<vector<int> > &input) {
if (input.size() > input[0].size()) {
affixRows(input, input.size() - input[0].size());
} else if (input.size() > input[0].size()) {
affixCols(input, input[0].size() - input.size());
}
}

void affixRows(vector<vector<int>> &input, int dimDiff) {
vector<vector<int>> temp(input.size(), vector<int>(input[0].size() + dimDiff));
for (unsigned int i = 0; i < temp[0].size(); i++) {
for (unsigned int j = 0; j < temp.size(); j++) {
if (i < (unsigned int)dimDiff / 2) {
temp[j][i] = 255;
}
else if (i < input[0].size() + (int)dimDiff / 2) {
temp[j][i] = input[j][i - (int)dimDiff / 2];
}
else {
temp[j][i] = 255;
}
}
}
input = temp; // point of mutation
}

void affixCols(vector<vector<int>> &input, int dimDiff) {
vector<vector<int>> temp(input.size() + dimDiff, vector<int>(input[0].size()));
for (unsigned int i = 0; i < temp[0].size(); i++) {
for (unsigned int j = 0; j < temp.size(); j++) {
if (j < (unsigned int)dimDiff / 2) {
temp[j][i] = 255;
}
else if (j < input.size() + (int)dimDiff / 2) {
temp[j][i] = input[j - (int)dimDiff / 2][i];
}
else {
temp[j][i] = 255;
}
}
}
input = temp; // point of mutation
}


I get these errors:

error: invalid initialization of non-const reference of type 'std::vector<std::vector<int> >&' from an rvalue of type 'std::vector<std::vector<int> >'
normalize(inList.front().getPix());
-------------------------------^--


If instead of:

normalize(inList.front().getPix());


I make a temporary vector and use that, it goes without error.

vector<vector<int> > temp = inList.front().getPix();
normalize(temp);


But this won't accomplish what I want, which is mutating the
pixelData
of a
characterData
. Why can I not access
pixelData
directly for the purpose of mutation?

Answer Source

You're mixing up the use of pointers and references.

In the function void processHandler(list<characterData> *inList), inList is a pointer, but the code within the function uses it as a reference.

while (!inList.empty())
{
    normalize(inList.front().getPix());
    inList.pop_front();
}

needs to treat inList as a pointer. So replace inList. with inList->.

while (!inList->empty())
{
    normalize(inList->front().getPix());
    inList->pop_front();
}

This will give a second problem as characterData::getPix() returns by value. but normalize() expects a reference (so the compiler will complain about something akin to passing a reference to a temporary - the temporary holds the value returned by getPix(), which will be a copy of the pixelData). Instead, to use it this way, getPix() needs to return a reference.

vector<vector<int> > &getPix() {return pixelData;}    // note the ampersand

This addresses your question AS ASKED. More generally, your design is fatally flawed - a member function of characterData that provides direct access (by pointer or reference) to any private member is a bad idea, since it allows any code to change that member. If you are going to do this, you might as well make the members public rather than private.

You need to provide member functions for characterData that allow a caller to REQUEST changes of private member functions (e.g. to add elements). These functions can - if you choose - ignore such requests. More importantly, they allow your class and its member functions, to collectively ensure the data is always in a valid state. Which is not possible if a caller can make arbitrary changes.