user4168715 user4168715 - 13 days ago 6
C++ Question

Object Slicing symptoms with reference to an object

I am facing a really weird issue with my class. Specifically, when I am passing "this" using the dereference operator to my non member function (*this), I am experiencing erroneous behavior of my argObj (members losing data etc.).
However, if I pass the "this" as a pointer to my non member function, everything works fine.

The issue with the first approach, is that the members of the argObj at some point start losing their data. I am querying the data realA, and pointerToA, and after some time they are losing their original data, without me messing with them.

So the question is, what exactly is happening when I am dereferencing the object using the *this semantic? If the argObj grows significantly in my non member function, will it be reallocated properly to a new address?

Here I have an example of what my code looks like. With these small objects I cannot replicate my problem.

NOT WORKING

#include <iostream>
#include <vector>
using namespace std;

class Base;
class Der;

struct collection {
vector<int> A;
vector<int> B;
};

void nonMemberFunc(Der & argObj);

class Base {
public:
collection * pointerToCol;
Base(collection &arg): pointerToCol(&arg) {}
virtual void myMemberFunc(){};
};
class Der: public Base {
public:
collection realCol;
Der():Base(realCol) {}
void myMemberFunc(){
nonMemberFunc(*this);
}
};

void nonMemberFunc(Der & argObj) {
// do things with the argObj (probably inflate its size)

for(int i = 0; i < 100; ++i) {
argObj.pointerToCol->A.push_back(i);
}

for(int i = 0; i < 1000; ++i) {
argObj.pointerToCol->B.push_back(i);
}

for(auto const & v :argObj.pointerToCol->A) {
cout << "A " << v << endl; // In my code, here A has wrong elements
}
for(auto const & v :argObj.pointerToCol->B) {
cout << "B " << v << endl;
}

}



int main () {
Der object;
Base * point = &object;
point->myMemberFunc();

}


WORKING

#include <iostream>
#include <vector>
using namespace std;

class Base;
class Der;

struct collection {
vector<int> A;
vector<int> B;
};

void nonMemberFunc(Der * argObj);

class Base {
public:
collection * pointerToCol;
Base(collection &arg): pointerToCol(&arg) {}
virtual void myMemberFunc(){};
};
class Der: public Base {
public:
collection realCol;
Der():Base(realCol) {}
void myMemberFunc(){
nonMemberFunc(this);
}
};

void nonMemberFunc(Der * argObj) {
// do things with the argObj (probably inflate its size)

for(int i = 0; i < 100; ++i) {
argObj->pointerToCol->A.push_back(i);
}

for(int i = 0; i < 1000; ++i) {
argObj->pointerToCol->B.push_back(i);
}

for(auto const & v :argObj->pointerToCol->A) {
cout << "A " << v << endl; // In my code here A has correct elements
}
for(auto const & v :argObj->pointerToCol->B) {
cout << "B " << v << endl;
}

}



int main () {
Der object;
Base * point = &object;
point->myMemberFunc();

}

Answer

It would appear that your implementation is falling victim to object slicing. Dereferencing the object (*this) is turning your Der object into a Base object (remember that you did Base * point = &object;). Calling point->myMemberFunc() is being done with point as a Base*. So when you dereference it in your code, you end up with a Base which is cast to a Der and taken by reference into your function. This ends up slicing some of your object away and you lose some of the polymorphic properties of Der. Passing the pointer around preserves polymorphism and doesn't slice your object.

Comments