I have faced with one rather interesting bug which was related to a wrong usage of casts. It is a great pleasure for me to share the results of the research. So the details are below. (For more details please take a look at my other article)
In one of the projects I was involved we had a class "
C" derived from two classes "
A" and "
class C : public A, public B
We had a vector of pointers on
C class and a function to find the index of a given pointer.
B* ptr = reinterpret_cast<B*>(cPointer);
int index = FindIndex(vectorOfCPointers, ptr);
FindIndex function we had a following code:
for (size_t i = 0; i < ptrVector.size(); ++i)
if (ptr == static_cast<B*>(ptrVector.at(i)))
The result of this function was always -1, so it was look like that there is no object even if it was there.
I think that it's easy to understand how to fix this bug. We should just change
reinterpret_cast outside the function onto
static_cast. We will get a different pointer values with a different casts. For example if
cPtr is equal to 0x11223344 as a result
of casts we will get a following values:
static_cast<B*>(cPtr) will be 0x11223348
reinterpret_cast<B*>(cPtr) will be 0x11223344
Let's find out why did it
happened. First of all we should know that object without virtual functions is represented in memory like a simple structure. It has all its fields
placed in memory with the same order like they were declared in a class definition. For example if we have a class like this:
And we have a pointer "
ptr" on the object of that class. We can have a direct
access to class fields like this.
int * aPtr = (int*)ptr;
int* bPtr = ((int*)ptr ) + 1;
int* cPtr = ((int*)bptr) + 1;
So what will happened in a case of multiple inheritance? For example we have our classes A, B, and C. Class C in memory will look like a sequence of classes A, B and C. And the pointer to the C class will point the sequence of fields of A class, fields of B class and finally fields of C class.
| cPtr ->||Class A members |
Class B members
|Class C members|
So what should happen if we want to cast
cPtr to the
bPtr? Right, we should add the size of A members to
cPtr, so we will get
bPtr points on the B class.
|Class A members |
|bPtr -> ||Class B members |
|Class C members |
As we can see
did that transformation but