public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* sizeof with virtual inheritance
@ 2004-04-27  4:50 Adrian Sandor
  2004-04-27 12:13 ` Eljay Love-Jensen
  0 siblings, 1 reply; 7+ messages in thread
From: Adrian Sandor @ 2004-04-27  4:50 UTC (permalink / raw)
  To: gcc-help

Hello,
I would like to know why the size of class objects grows when virtual
inheritance is involved. I suppose the compiler adds some extra pointers to
them; I would like to know what they are for and why they are necessary, and if
it's possible to avoid them (or use at most one extra pointer).
I googled for this a bit, and I found an answer which suggests the use of an
attribute called "onevtable", but I can't find any other reference about it.
I'm using gcc 3.2 (I know, I know..) on Windows (mingw). I could switch to gcc
3.3.x if necessary.

Thanks
Adrian

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: sizeof with virtual inheritance
  2004-04-27  4:50 sizeof with virtual inheritance Adrian Sandor
@ 2004-04-27 12:13 ` Eljay Love-Jensen
  2004-05-07 19:39   ` Adrian Sandor
  0 siblings, 1 reply; 7+ messages in thread
From: Eljay Love-Jensen @ 2004-04-27 12:13 UTC (permalink / raw)
  To: Adrian Sandor, gcc-help

Hi Adrian,

 >I would like to know why the size of class objects grows when virtual 
inheritance is involved.

The structure has extra bookkeeping information to keep track.

For example, if you have multiple inheritance of:
foo : bar
baz : bar
quux : foo, baz

The memory layout of quux is going to be:
bar
foo
baz
quux

If you pass a quux to something that expects a baz, that routine would expect:
bar
baz

...it wouldn't expect a "foo" stuck in the middle.

The extra "behind the scenes" bookkeeping information is used to take care 
of that situation.

I do not think that it is a "onevtable" (whatever that is) related issue.

HTH,
--Eljay

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: sizeof with virtual inheritance
  2004-04-27 12:13 ` Eljay Love-Jensen
@ 2004-05-07 19:39   ` Adrian Sandor
  2004-05-07 20:30     ` Eljay Love-Jensen
  0 siblings, 1 reply; 7+ messages in thread
From: Adrian Sandor @ 2004-05-07 19:39 UTC (permalink / raw)
  To: gcc-help

Eljay Love-Jensen writes:
> The structure has extra bookkeeping information to keep track.
> 
> For example, if you have multiple inheritance of:
> foo : bar
> baz : bar
> quux : foo, baz
> 
> The memory layout of quux is going to be:
> [...]

Hi, sorry for the late reply

Your comments apply generally to multiple inheritance, you didn't say anything
about virtual inheritance. Besides, for non-virtual multiple inheritance, there
seems to be no extra data in the objects.
Here is a program that shows what I'm talking about:

//--------8<---------
#include <iostream>

using namespace std;

class c1{char x;};
class c2:public c1{};
class c3:public c1{};
class c4:virtual public c1{};
class c5:virtual public c1{};
class c6:public c2, public c3{};
class c7:public c4, public c5{};

#define S(x) cout<<"c"#x<<": "<<sizeof(c##x)<<endl;

int main()
{
	S(1)S(2)S(4)S(6)S(7)
	cin.get();
}
//------->8---------

I compiled it with mingw - gcc 3.2 (in Windows) and here are the results:

c1: 1
c2: 1
c4: 8
c6: 2
c7: 12

I had the same results on a linux system too.

As you can see, the only difference between c2 and c4 is the virtual
inheritance, yet the size difference is 7 bytes (it probably has an extra 4-byte
pointer aligned at a 4-byte offset).
Classes c6 and c7 have multiple inheritance (basically they both inherit c1
twice, indirectly), and again the difference is virtual inheritance.
c6 really gets 2 copies of c1, so the size is 2.
But c7 should only get 1 copy of c1 because of the virtual inheritance; yet its
size is 12, which suggests it has 2 extra pointers or something.

I'd like to know what's that extra data used for and why it is necessary. I'd
also like to know when and where it is added, because I haven't managed to find
an algorithm to calculate the size based on the inheritance graph.

Thanks
Adrian

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: sizeof with virtual inheritance
  2004-05-07 19:39   ` Adrian Sandor
@ 2004-05-07 20:30     ` Eljay Love-Jensen
  2004-05-07 20:38       ` Eljay Love-Jensen
  2004-05-07 20:50       ` Adrian Sandor
  0 siblings, 2 replies; 7+ messages in thread
From: Eljay Love-Jensen @ 2004-05-07 20:30 UTC (permalink / raw)
  To: Adrian Sandor, gcc-help

Hi Adrian,

 >Your comments apply generally to multiple inheritance, you didn't say 
anything about virtual inheritance.

No, my comments were specifically about virtual inheritance.

Look at the memory layout of c4, which is 8 bytes:
c4 : byte[0 ... 3]
c4.c1 : byte[4]
c4.pad : byte[5 ... 7]

Those [0 ... 3] four bytes for the c4 portion (alone) of c4 contains the 
pointer for the multiple inheritance overhead.

- - - - - -

Look at the memory layout of c6, which is 2 bytes:
c6.c2.c1 : byte[0]
c6.c2.c3.c1 : byte[1]

Nothing interesting here.  Straightforward.

- - - - - -

Look at the memory layout of c7, which is 12 bytes:
c7.c4 : byte[0 ... 3]
c7.c5. : byte [4 ... 7]
c7.c4.c1 & c7.c5.c1 : byte[8]
c7.pad : byte[9 ... 11]

The [0 ... 3] four bytes for the c7.c4 portion (alone) contains the c4 
pointer for the multiple inheritance.

The [4 ... 7] four bytes for the c7.c5 portion contains the c5 pointer for 
the multiple inheritance.

The padding is alignment padding.

HTH,
--Eljay

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: sizeof with virtual inheritance
  2004-05-07 20:30     ` Eljay Love-Jensen
@ 2004-05-07 20:38       ` Eljay Love-Jensen
  2004-05-07 20:50       ` Adrian Sandor
  1 sibling, 0 replies; 7+ messages in thread
From: Eljay Love-Jensen @ 2004-05-07 20:38 UTC (permalink / raw)
  To: Adrian Sandor, gcc-help

Ooops, had a typo in the uninteresting section:

Look at the memory layout of c6, which is 2 bytes:
c6.c2.c1 : byte[0]
c6.c3.c1 : byte[1]

--Eljay

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: sizeof with virtual inheritance
  2004-05-07 20:30     ` Eljay Love-Jensen
  2004-05-07 20:38       ` Eljay Love-Jensen
@ 2004-05-07 20:50       ` Adrian Sandor
  2004-05-07 23:42         ` Eljay Love-Jensen
  1 sibling, 1 reply; 7+ messages in thread
From: Adrian Sandor @ 2004-05-07 20:50 UTC (permalink / raw)
  To: gcc-help

Eljay Love-Jensen writes:

> No, my comments were specifically about virtual inheritance.

Well, here's what you wrote:

> For example, if you have multiple inheritance of:
> foo : bar
> baz : bar
> quux : foo, baz

You probably implied it, but you didn't mention virtual inheritance, so I
thought you didn't talk about it. Nevermind :)

> Look at the memory layout of c4, which is 8 bytes:
> c4 : byte[0 ... 3]
> c4.c1 : byte[4]
> c4.pad : byte[5 ... 7]
> 
> Those [0 ... 3] four bytes for the c4 portion (alone) of c4 contains the 
> pointer for the multiple inheritance overhead.

How can I see the layout like that?
And what is the actual use of that "pointer for the multiple inheritance
overhead"? What does it point to and when and how is it used?

[removed comment about "c6.c2.c3.c1" because you replied about it]

> The padding is alignment padding.

Is it possible to disable it, especially that it's at the end of the layout?

Thanks
Adrian

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: sizeof with virtual inheritance
  2004-05-07 20:50       ` Adrian Sandor
@ 2004-05-07 23:42         ` Eljay Love-Jensen
  0 siblings, 0 replies; 7+ messages in thread
From: Eljay Love-Jensen @ 2004-05-07 23:42 UTC (permalink / raw)
  To: Adrian Sandor, gcc-help

Hi Adrian,

 >How can I see the layout like that?

I just enhanced your example.

$ cat Adrian.cpp
#include <iostream>

using namespace std;

struct c1{char x; void p1() const;};
struct c2:public c1{void p2() const;};
struct c3:public c1{void p3() const;};
struct c4:virtual public c1{void p4() const;};
struct c5:virtual public c1{void p5() const;};
struct c6:public c2, public c3{void p6() const;};
struct c7:public c4, public c5{void p7() const;};

#define P(x) \
void c##x::p##x() const \
{ \
         cerr << "c" #x ":" << (void*)this << endl; \
}

P(1)
P(2)
P(3)
P(4)
P(5)
P(6)
P(7)


#define S(x) cout<<"c"#x<<": "<<sizeof(c##x)<<endl;

int main()
{
         S(1)S(2)S(4)S(6)S(7)

         cerr << "\nc4...\n";
         c4 o4;
         o4.p1();
         o4.p4();

         cerr << "\nc6...\n";
         c6 o6;
         //o6.p1(); -- ambiguous
         o6.p2();
         o6.p3();
         o6.p6();

         cerr << "\nc7...\n";
         c7 o7;
         //o7.p1(); -- ambiguous
         ((c4&)o7).p1();
         ((c5&)o7).p1();
         o7.p4();
         o7.p5();
         o7.p7();
         //cin.get();
}

 >And what is the actual use of that "pointer for the multiple inheritance 
overhead"?

Multiple inheritance incurs a potential extra level of indirection.

 >What does it point to and when and how is it used?

I believe it points to a class layout map.  When a multiple-inherited 
object is passed to a routine -- especially one that takes one of it's 
parent class types -- it has to take into account that the memory layout 
may be something unexpected.

This descrambling of multiple-inheritance is different from that of the 
virtual function table.  But both have the similarity of adding overhead.

 >Is it possible to disable it, especially that it's at the end of the layout?

Yes, you can disable it using the GCC __attribute__((packed)) 
decoration.  But I strongly suggest you don't do that, since (likely) 
you'll make the class unusable in an array, non-inheritable, and not able 
to be used as a member variable in another class.

And the __attribute__ extension is a GCC-ism.

HTH,
--Eljay

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2004-05-07 23:42 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-04-27  4:50 sizeof with virtual inheritance Adrian Sandor
2004-04-27 12:13 ` Eljay Love-Jensen
2004-05-07 19:39   ` Adrian Sandor
2004-05-07 20:30     ` Eljay Love-Jensen
2004-05-07 20:38       ` Eljay Love-Jensen
2004-05-07 20:50       ` Adrian Sandor
2004-05-07 23:42         ` Eljay Love-Jensen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).