hagiwara@zuken.co.jp (Kazuyuki Hagiwara) (10/18/90)
I am using AT&T C++ version 2.0. Following is the simple test of multipile inheritance with virtual base classes. Do anyone know the reason why sizeof(D) is so large ? I think sizeof(D) should be only 1000 bytes and some pointer overhead. ----------------------------- mibug.C { ---------------- #include <iostream.h> struct A { char avar0[1000]; }; struct B : virtual public A { int bvar; }; struct C : virtual public A { int cvar; }; struct D : virtual public B, virtual public C { int dvar; }; main() { A a1; B b1; C c1; D d1; cout << "sizeof A: " << sizeof(A) << endl; cout << "sizeof B: " << sizeof(B) << endl; cout << "sizeof C: " << sizeof(C) << endl; cout << "sizeof D: " << sizeof(D) << endl; } ----------------------------- } mibug.C ---------------- ----- output of mibug { ------- sizeof A: 1000 sizeof B: 1008 sizeof C: 1008 sizeof D: 2032 ----- output of mibug } ------- -- Kazuyuki Hagiwara @ Zuken, Inc. Yokohama, Japan (hagiwara@zuken.co.jp)
sking@nowhere.uucp (Steven King) (10/22/90)
In article <HAGIWARA.90Oct18105013@rd14.zuken.co.jp> hagiwara@zuken.co.jp (Kazuyuki Hagiwara) writes: > >I am using AT&T C++ version 2.0. Following is the simple test of >multipile inheritance with virtual base classes. Do anyone know >the reason why sizeof(D) is so large ? I think sizeof(D) should be >only 1000 bytes and some pointer overhead. > >----------------------------- mibug.C { ---------------- >#include <iostream.h> > >struct A { > char avar0[1000]; >}; > >struct B : virtual public A { > int bvar; >}; > >struct C : virtual public A { > int cvar; >}; > >struct D : virtual public B, virtual public C { > int dvar; >}; The definitions of B and C each have space for A allocated within them; thus the size of D is sizeof B ( which is sizeof A + pointer overhead ) + sizeof C ( sizeof A + pointer overhead ) + more pointer overhead. A little thought on how virtual bases are implemented should reveal why this is, tho' I'm not sure that a smarter Cfront might only need to alloc space for it once. -- sking@nowhere | C++ is to C, what espresso is to coffee; ..!cs.utexas.edu!ut-emx!nowhere!sking | Definitely an acquired taste, but once | you have acquired that taste, you cant | go back ...
steve@taumet.com (Stephen Clamage) (10/22/90)
sking@nowhere.uucp (Steven King) writes: |In article |HAGIWARA.90Oct18105013@rd14.zuken.co.jp> hagiwara@zuken.co.jp (Kazuyuki Hagiwara) writes: |> [ ... ] |>struct A { |> char avar0[1000]; |>}; |>struct B : virtual public A { |> int bvar; |>}; |>struct C : virtual public A { |> int cvar; |>}; |>struct D : virtual public B, virtual public C { |> int dvar; |>}; | The definitions of B and C each have space for A allocated within them; |thus the size of D is sizeof B ( which is sizeof A + pointer overhead ) + |sizeof C ( sizeof A + pointer overhead ) + more pointer overhead. This is not correct. Exactly one instance of a virtual base class exists in an object by definition. Class A is declared to be virtual in all uses of it, so it is an error for there to be more than one copy. Let us hope that the error in this case is in the allocation, and that only one copy is ever referred to by generated code. -- Steve Clamage, TauMetric Corp, steve@taumet.com
vaughan@mcc.com (Paul Vaughan) (10/22/90)
The discussion between Kazuyuki Hagiwara and Steven King about the sizes of muliply and virtually derived objects is curious indeed. Here is what GNU C++ does, followed by cfront 2.0 (Sun C++). #include <stream.h> struct A { char avar0[1000]; }; struct B : virtual public A { int bvar; }; struct C : virtual public A { int cvar; }; struct D : virtual public B, virtual public C { int dvar; }; main() { cout << "A " << sizeof(A) << " B " << sizeof(B) << " C " << sizeof(C) << " D " << sizeof(D) << "\n"; } bash$ g++ -o trash trash.cc bash$ trash A 1000 B 1008 C 1008 D 1028 <= reasonable bash$ CC -o trash trash.cc CC trash.cc: cc -o /d2/prism/prism/src/sim/src/trash -I/net/sunspot/usr/cadsw/CC/sun4/incl trash.c -L/net/sunspot/usr/cadsw/CC/sun4/ -lC bash$ trash A 1000 B 1008 C 1008 D 2032 <= unreasonable Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639 Box 200195, Austin, TX 78720 | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan
jamiller@hpcupt1.cup.hp.com (Jim Miller) (10/25/90)
IMHO: the 2K size is a bug. E&S's ARM, 10.1: " class V { /* ... */ }; class A : virtual public V { /* ... */ }; class B : virtual public V { /* ... */ }; class C : public A, public B { /* ... */ }; Here class C has only one sub-object of class V. " jim miller jamiller@hpmpeb7.cup.hp.com (a.k.a James A. Miller; Jim the JAM; stupid; @!?$$!; ... ) Anything I say will be used against me ... But my company doesn't know or approve or condone anything of mine here.
Reid Ellis <rae@gpu.utcs.toronto.edu> (10/25/90)
The source being discussed is appended at the end of this article after a linefeed. I noticed that the struct 'D' does not need to use "virtual" for deriving from B and C [although it shouldn't matter for this code] and tried removing them. Under Apple's MPW C++ compiler, I get the previously mentioned cfront output: A 1000 B 1008 C 1008 D 2032 If, however, I change the line "struct D : virtual public B, virtual public C {" to "struct D : public B, public C {" then I get the more expected result of: A 1000 B 1008 C 1008 D 1020 Hope this pins the problem down a bit more. And if you need to, use this as a workaround. Reid Original source follows: #include <stream.h> struct A { char avar0[1000]; }; struct B : virtual public A { int bvar; }; struct C : virtual public A { int cvar; }; struct D : virtual public B, virtual public C { int dvar; }; main() { cout << "A " << sizeof(A) << " B " << sizeof(B) << " C " << sizeof(C) << " D " << sizeof(D) << "\n"; } -- Reid Ellis 264 Broadway Avenue, Toronto ON, M4P 1V9 Canada rae@gpu.utcs.toronto.edu || rae%alias@csri.toronto.edu || +1 416 487 1383
shankar@hpclscu.HP.COM (Shankar Unni) (10/26/90)
> IMHO: the 2K size is a bug. > E&S's ARM, 10.1: " > > class V { /* ... */ }; > class A : virtual public V { /* ... */ }; > class B : virtual public V { /* ... */ }; > class C : public A, public B { /* ... */ }; > > Here class C has only one sub-object of class V. " Yes, and if you feed this case to cfront, it gives the "right" answer (1020). It's when C derives from a virtual A and a virtual B that things get interesting. I think it's a cfront bug, too. ----- Shankar Unni. HP Calif. Language Lab.
sking@nowhere.uucp (Steven King) (10/27/90)
In article <488@taumet.com> steve@taumet.com (Stephen Clamage) writes: >sking@nowhere.uucp (Steven King) writes: > >|In article |HAGIWARA.90Oct18105013@rd14.zuken.co.jp> hagiwara@zuken.co.jp (Kazuyuki Hagiwara) writes: >|> >[ ... ] >|>struct A { >|> char avar0[1000]; >|>}; >|>struct B : virtual public A { >|> int bvar; >|>}; >|>struct C : virtual public A { >|> int cvar; >|>}; >|>struct D : virtual public B, virtual public C { >|> int dvar; >|>}; > >| The definitions of B and C each have space for A allocated within them; >|thus the size of D is sizeof B ( which is sizeof A + pointer overhead ) + >|sizeof C ( sizeof A + pointer overhead ) + more pointer overhead. > >This is not correct. Exactly one instance of a virtual base class exists >in an object by definition. Class A is declared to be virtual in all uses >of it, so it is an error for there to be more than one copy. Let us hope >that the error in this case is in the allocation, and that only one copy >is ever referred to by generated code. ( sigh ) It is correct as a simple test and examination of the C output would have shown. To wit: struct A { /* sizeof A == 1000 */ char avar0__1A [1000]; }; struct B { /* sizeof B == 1008 */ int bvar__1B ; struct A *PA; struct A OA; }; struct C { /* sizeof C == 1008 */ int cvar__1C ; struct A *PA; struct A OA; }; struct D { /* sizeof D == 2032 */ int dvar__1D ; struct C *PC; struct B *PB; struct A *PA; struct C OC; struct B OB; }; Each class has space allocated for the virtual base, and has a pointer to the virtual base it actually uses. The constructors are passed a pointer to the virtual base they are to use. Tf the pointer is NULL, they initialize it, call the constructor for the virtual base, and pass it to the constructors for the classes they are derived from. Its pretty straight forward, tho' the code generated can be rather dense.... and now for a slight flame.... Am I the only person using Cfront who checks the C output when there is a question about what it is doing? If one is using Cfront and has a question about what is going on (especially in one's own code), there is no excuse for not examining the C output. If the lack of formatting bothers you, then run it thru cb ( I edited my CC script to do it automatically for me ) Or are there a bunch of C weenies out there who cant stand the sight of raw C code ;-} regards, -- sking@nowhere | C++ is to C, what espresso is to ..!cs.utexas.edu!ut-emx!nowhere!sking | coffee; Definitely an acquired taste, | but once you have acquired that taste, | you cant go back ...
dans@microsoft.UUCP (Dan SPALDING) (10/28/90)
In article <488@taumet.com> steve@taumet.com (Stephen Clamage) writes: >sking@nowhere.uucp (Steven King) writes: > >|In article |HAGIWARA.90Oct18105013@rd14.zuken.co.jp> hagiwara@zuken.co.jp (Kazuyuki Hagiwara) writes: > >This is not correct. Exactly one instance of a virtual base class exists >in an object by definition. Class A is declared to be virtual in all uses >of it, so it is an error for there to be more than one copy. Let us hope >that the error in this case is in the allocation, and that only one copy >is ever referred to by generated code. >-- > >Steve Clamage, TauMetric Corp, steve@taumet.com while that is technically true, cfront generates structure defn's that are not in any way optimal. The space for both the A part of B and C are in B and C, and the class D includes both of these structures and a pointer to the shared A (which is one of the ones in B or C). So, from the user's point of view, there is only one A, but the space for two of them is consumed. Not very neat is it? here is an example of mi.cxx and it's resultant mi.c from Glock 2.0: mi.cxx: class A { char _rgb[1000]; }; class B : public virtual A { int _w; }; class C : public virtual A { int _w; }; class D : public virtual B, public virtual C { int _w; }; main () { D * pd; }; mi.c: #line 1 "mi.cxx" /* << cfxx :- 2.0 Msoft a >> */ /* < mi.cxx > */ static void __cvp30_support(void) {} void * __vec_new ( void * , int , int , void * ) #line 1 ; #line 1 void __vec_delete ( void * , int , int , void * , int #line 1 , int ) ; typedef int (*__vptp)(); struct __mptr {short d; short i; __vptp f; }; static void _cdecl _STI(); static void _cdecl _STD(); #line 1 struct A; struct A { /* sizeof A == 1000 */ char _rgb__1A [ 1000] ; }; struct B; struct B { /* sizeof B == 1006 */ int _w__1B ; struct A * PA; struct A OA; }; #line 1 extern void * __nw__FUi ( unsigned int ) ; struct C; #line 7 struct C { /* sizeof C == 1006 */ int _w__1C ; struct A * PA; struct A OA; }; struct D; #line 9 #line 6 #line 10 struct D { /* sizeof D == 2026 */ int _w__1D ; struct C * PC; struct B * PB; struct A * PA; struct C OC; struct B OB; }; #line 14 int main ( void ) { { struct D * pd ; } } #line 16 /* the end */ ------------------------------------------------------------------------ dan spalding -- microsoft systems/languages -- microsoft!dans "there has not been a word invented that would convey my indifference to that remark." - paraphrase from hawkeye pierce ------------------------------------------------------------------------
sking@nowhere.uucp (Steven King) (10/29/90)
Unfortunately, my newsfeed is about 4 days behind the rest of the world, and after getting somewhat caught up on my reading of this group, I thought I had stuck my foot in it... However, after further thought, I still believe that my interpretation of what Cfront is doing and why it is doing what it is doing is correct =-} In article <12342@cadillac.CAD.MCC.COM> vaughan@mcc.com (Paul Vaughan) writes: >The discussion between Kazuyuki Hagiwara and Steven King about the >sizes of muliply and virtually derived objects is curious indeed. >Here is what GNU C++ does, followed by cfront 2.0 (Sun C++). [ code already repeated several times not shown ] >bash$ g++ -o trash trash.cc >bash$ trash >A 1000 B 1008 C 1008 D 1028 <= reasonable >bash$ CC -o trash trash.cc >CC trash.cc: >cc -o /d2/prism/prism/src/sim/src/trash -I/net/sunspot/usr/cadsw/CC/sun4/incl trash.c -L/net/sunspot/usr/cadsw/CC/sun4/ -lC >bash$ trash >A 1000 B 1008 C 1008 D 2032 <= unreasonable Curious indeed! The result from g++ is what I thought a better engineered Cfront might do, however, I now think that g++ is wrong. ( see below ) In article <rae.656801817@fred> rae@gpu.utcs.toronto.edu (Reid Ellis) writes: >The source being discussed is appended at the end of this article >after a linefeed. I noticed that the struct 'D' does not need to use >"virtual" for deriving from B and C [although it shouldn't matter for >this code] and tried removing them. > >Under Apple's MPW C++ compiler, I get the previously mentioned cfront >output: >A 1000 B 1008 C 1008 D 2032 > >If, however, I change the line >"struct D : virtual public B, virtual public C {" >to >"struct D : public B, public C {" >then I get the more expected result of: >A 1000 B 1008 C 1008 D 1020 > >Hope this pins the problem down a bit more. And if you need to, use >this as a workaround. > Reid This, I believe is paramount to the question at hand. The declarations of B and C as virtual to D do affect how subsequent derivations are treated. In article <7050032@hpcupt1.cup.hp.com> jamiller@hpcupt1.cup.hp.com (Jim Miller) writes: > >IMHO: the 2K size is a bug. > > >E&S's ARM, 10.1: " > > class V { /* ... */ }; > class A : virtual public V { /* ... */ }; > class B : virtual public V { /* ... */ }; > class C : public A, public B { /* ... */ }; > > Here class C has only one sub-object of class V. " yes, but thats a different matter.... Now to the nexus of the question. Given the aforementioned definitions of A, B, C, and D, we derive class E : public virtual B { int evar; } ; class F : public D, public E { int fvar ; } ; now F::E and F::D not only share a common A, but a common B as well. However, methods that act upon E do not know anything D or D's defintion of B. If, the definition of D is such that B and C are collapsed together as it appears that g++ is doing, then E's methods, with compiler generated offsets into B, are, in fact, going to munge C or D. Only Cfront's inclusion of a complete B into D is going to prevent this. This might not be appearent given the above examples, as they are simple enought that the translator/complier could guarantee proper ordering of members, but with arbitrarily complex definitions I dont believe this would always be true. Of course, I could be wrong and this could be a bug in the implementation of Cfront. If so, then I'm sure there is someone out there in netland willing to correct me. =-} -- sking@nowhere | C++ is to C, what espresso is to ..!cs.utexas.edu!ut-emx!nowhere!sking | coffee; Definitely an acquired taste, | but once you have acquired that taste, | you cant go back ...
bashford@scripps.edu (Don Bashford) (10/30/90)
In article <1990Oct29.054455.1989@nowhere.uucp> sking@nowhere.uucp (Steven King) writes: > now F::E and F::D not only share a common A, but a common B as well. > However, methods that act upon E do not know anything D or D's defintion of > B. If, the definition of D is such that B and C are collapsed together as it > appears that g++ is doing, then E's methods, with compiler generated offsets > into B, are, in fact, going to munge C or D. Aren't you confusing classes with *instances* of classes? Don Bashford bashford@scripps.edu