virtual-multiple inheritance. what an extra dword is for?

V

Vladimir_petter

Hello All,

I've fount that if I compile the same program using gcc and vc 2003 the same class E (see complete source bellow) has different size (on vc it is 4 bytes bigger). Digging into this I've found that vc is reserving a dword in the E class right before storage for virtual base class. In my tests value of this dword always was 0. I did not see any code referencing this memory.

Anybody has any idea what this dword is for?

Vladimir.


/*

Compile:
cl -EHsc -Zi t11.cpp

Classes hierarchy
A
/ \
| |
| |
B D C
| | |
| | |
\ | /
E

Output: My Interpritation:

ma=ff1, sizeof(A)=8 sizeof(vtable) + sizeof(ma_)
mb=ff2, sizeof(B)=20 sizeof(vtable) + sizeof(mb_) + 1*sizeof(DWORD) + sizeof(A)
mc=ff3, sizeof(C)=20 sizeof(vtable) + sizeof(mb_) + 1*sizeof(DWORD) + sizeof(A)
md=ff4, sizeof(D)=8 sizeof(vtable) + sizeof(md_)
me=ff5, sizeof(E)=40
&before - &after = 13

Layout of the stack in the "main" function:

Nr Address Value Points to My Interpritation
01 0012feb0 00000fe2 << veriable "after"

02 0012feb4 0041f178 t11!E::`vftable' << veriable e, start of E, start of E::D
03 0012feb8 00000ff4 << e.md_
04 0012febc 0041f188 t11!E::`vbtable' << start of E::B
05 0012fec0 00000ff2 << e.mb_
06 0012fec4 0041f17c t11!E::`vbtable' << start of E::C
07 0012fec8 00000ff3 << e.mc_
08 0012fecc 00000ff5 << e.me_
09 0012fed0 00000000 << ???WHAT ARE THIS FOR???
10 0012fed4 0041f174 t11!E::`vftable' << start of E::A
11 0012fed8 00000ff1 << e.ma_, end of E
12 0012fedc 0000000c << veriable "distance"

13 0012fee0 00000fe1 << veriable "before"

*/

#include<iostream>

using namespace std;

class A {
public:
explicit A(long ma)
: ma_(ma) {
}
virtual void foo();
private:
long ma_;
};

void A::foo() {
cout << hex << "ma=" << ma_ << ", sizeof(A)=" << dec << sizeof(A) << "\n";
}

class B : public virtual A {
public:
explicit B(long mb)
: mb_(mb), A(0) {
}
virtual void foo();
private:
long mb_;
};

void B::foo() {
cout << hex << "mb=" << mb_ << ", sizeof(B)=" << dec << sizeof(B) << "\n";
}

class C : public virtual A {
public:
explicit C(long mc)
: mc_(mc), A(0) {
}
virtual void foo();
private:
long mc_;
};

void C::foo() {
cout << hex << "mc=" << mc_ << ", sizeof(C)=" << dec << sizeof(C) << "\n";
}

class D {
public:
explicit D(long md)
: md_(md) {
}
virtual void foo();
private:
long md_;
};

void D::foo() {
cout << hex << "md=" << md_ << ", sizeof(D)=" << dec << sizeof(D) << "\n";
}

class E : public B, public C, public D {
public:
explicit E(long ma=0xFF1, long mb=0xFF2, long mc=0xFF3, long md=0xFF4, long me=0xFF5)
: A(ma), B(mb), C(mc), D(md), me_(me) {
}
virtual void foo();
private:
long me_;
};

void E::foo() {
A::foo();
B::foo();
C::foo();
D::foo();
cout << hex << "me=" << me_ << ", sizeof(E)=" << dec << sizeof(E) << "\n";
}

int main(int, char **) {
cout << hex;

int distance = 0;
int before = 0xFE1;

E e;
if(!distance) { //to prevent compiler from rearanging veriables on the stack
int after = 0xFE2;
distance = &before - &after;
}
e.foo();

cout << dec << "&before - &after = " << abs(distance) << "\n";

return 0;
}
 
D

Doug Harrison [MVP]

Vladimir_petter said:
Hello All,

I've fount that if I compile the same program using gcc and vc 2003 the same class E (see complete source bellow) has different size (on vc it is 4 bytes bigger). Digging into this I've found that vc is reserving a dword in the E class right before storage for virtual base class. In my tests value of this dword always was 0. I did not see any code referencing this memory.

Anybody has any idea what this dword is for?

See if this article helps you figure it out:

C++: Under the Hood
Jan Gray
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnarvc/html/jangrayhood.asp
 
V

Vladimir_petter

Hello Doug,

Thanks for the link. It definetly helped.
I am still not 100% sure, but my guess is that this DWORD is a reservaton for a future vbtable to store deplacement of A relative to E.
See bellow corrected picture.

Thanks,
Vladimir.


Layout of the stack in the "main" function:

Nr Address Value Points to My Interpritation
01 0012feb0 00000fe2 << veriable "after"

02 0012feb4 0041f178 t11!E::`vftable' << veriable e, start of E, start of E::D ---------------
03 0012feb8 00000ff4 << e.md_ |
04 0012febc 0041f188 t11!E::`vbtable' << deplacement info for A relative to B------------- |
05 0012fec0 00000ff2 << e.mb_, start of E::b | |
06 0012fec4 0041f17c t11!E::`vbtable' << deplacement info for A relative to C-------- | |
07 0012fec8 00000ff3 << e.mc_ | | |
08 0012fecc 00000ff5 << e.me_ | | |
09 0012fed0 00000000 << ?is this a reservation for future vbtable? | | |
10 0012fed4 0041f174 t11!E::`vftable' << start of E::A---------------------------- | | |
11 0012fed8 00000ff1 << e.ma_, end of E | | | |
| | | |
12 0012fedc 0000000c << veriable "distance" | | | |
13 0012fee0 00000fe1 << veriable "before" | | | |
| | | |
| | | |
t11!E::`vftable' at 0041f174 <- | | |
0041f174 0040112c t11!ILT+295(?fooE$4PPPPPPPMCAAEXXZ)--------------------------- | | |
| | | |
t11!E::`vftable' at 0041f178: | | | |
0041f178 004012f3 t11!ILT+750(?fooEUAEXXZ)--------------------------------- | | | <-
| | | |
t11!E::`vbtable' at 0041f17c | | <- |
0041f17c 00000000 | | |
0041f180 00000010 << decimal 16, 4 dwords from C to A in E | | |
0041f184 00000000 | | |
| | |
t11!E::`vbtable' at 0041f188 | | <-
0041f188 00000000 | |
0041f18c 00000018 << decimal 24, 6 dwords from B to A in E | |
0041f190 00000000 | |
| |
t11!ILT+295(?fooE$4PPPPPPPMCAAEXXZ): | <-
0040112c e98f540000 jmp t11!E::foo (004065c0)-- |
| |
t11!E::foo: <- |
004065c0 2b49fc sub ecx,[ecx-0x4] |
004065c3 83e920 sub ecx,0x20 |
004065c6 e928adffff jmp t11!ILT+750(?fooEUAEXXZ) (004012f3)-- |
| |
t11!ILT+750(?fooEUAEXXZ): <- <-
004012f3 e9e8040000 jmp t11!E::foo (004017e0)--
|
t11!E::foo [t11.cpp @ 117]: <-
004017e0 55 push ebp
004017e1 8bec mov ebp,esp
004017e3 51 push ecx
004017e4 894dfc mov [ebp-0x4],ecx
004017e7 8b45fc mov eax,[ebp-0x4]
 
Top