Topic: Memory layout of derived classes when using single inheritance.


Author: richard_corden@hotmail.com (Richard Corden)
Date: Mon, 18 Sep 2006 17:32:09 GMT
Raw View
Hi,

I'm trying to get my head around some of the paragraph at the beginning
of chapter 10.

Firstly I'm trying to understand 10/3.  When it uses the term 'order in
which the base class subobjects are allocated', what order is it
referring to?  I think it implies *when* the base class subobjects are
allocated, rather than *where*.


A second question I have relates to 10/5, where it has a note which
mentions that a base class subobject may have a different layout to that
of a most derived object of the same type.  Under what kind of
conditions can this be true?


Any help appreciated,

Kind Regards,

Richard


--
Richard Corden

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 19 Sep 2006 03:44:24 GMT
Raw View
Richard Corden ha scritto:
> Hi,
>
> I'm trying to get my head around some of the paragraph at the beginning
> of chapter 10.
>
> Firstly I'm trying to understand 10/3.  When it uses the term 'order in
> which the base class subobjects are allocated', what order is it
> referring to?  I think it implies *when* the base class subobjects are
> allocated, rather than *where*.

I think it clearly implies *where*. There is no notion of time here,
10/3 is about how subobjects are laid out in memory, not the sequence of
events that bring those objects into existence (that is the subject of 3.8).

Another argument against the "when" interpretation is that the memory of
the whole most derived object is allocated in one operation and then
split into subobjects. The splitting step doesn't require any runtime
decision (because the layout is determined at compile time), so, in a
certain sense, all subobjects are allocated simultaneously.

> A second question I have relates to 10/5, where it has a note which
> mentions that a base class subobject may have a different layout to that
> of a most derived object of the same type.  Under what kind of
> conditions can this be true?

The wording here is explicitly granting latitude for both known and
future (not-yet-known) optimizations, so there's no definitive answer to
your question. Specific implementations may (and usually do) provide
documentation of class layout strategies, so if you are interested you
should read those.

Regards,

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: wade@stoner.com
Date: Tue, 19 Sep 2006 09:51:33 CST
Raw View
Richard Corden wrote:
> A second question I have relates to 10/5, where it has a note which
> mentions that a base class subobject may have a different layout to that
> of a most derived object of the same type.  Under what kind of
> conditions can this be true?

Virtual inheritance often does this:

class b{Bstuff};
class x: virtual b {Xstuff};  // layout might be XstuffBstuff
class y: virtual b {Ystuff};  // layout might be YstuffBstuff
class z: x,y {Zstuff};        // layout might be
XstuffYstuffZstuffBstuff

So a most-derived x object has one layout (XstuffBstuff), while an x
subobject may have a different layout (Xstuff...Bstuff).

Empty base optimization means that a base-class object may "shrink"
compared to its most-derived form.

Also consider

  class a { public: int w; protected: double x; };
  class b { public: int y; protected: double z; };
  class c: public a, b {};

'a' is not pod (because of protected:) so I believe a legal layout for
'a' is

     int w;
     double* __x_location;
     double x;

A legal layout for 'c' is
    int w;
    double* __x_location;
    int y;
    double* __z_location;
    double x;
    double z;

This might even make sense on some platforms for some access patterns.
Consider Itanium, which can't load/store floating-point registers from
L1 cache.  The integer/pointer portion of a 'c' object could fit nicely
in an L1 cache line, while the double portion would live out in the L2
cache.  I'd be a bit surprised to find out that anybody has done this
in a production compiler.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Wed, 20 Sep 2006 01:00:11 CST
Raw View
wade@stoner.com wrote:
> Richard Corden wrote:
> > A second question I have relates to 10/5, where it has a note which
> > mentions that a base class subobject may have a different layout to that
> > of a most derived object of the same type.  Under what kind of
> > conditions can this be true?
> ...
> Also consider
>
>   class a { public: int w; protected: double x; };
>   class b { public: int y; protected: double z; };
>   class c: public a, b {};
>
> 'a' is not pod (because of protected:) so I believe a legal layout for
> 'a' is
>
>      int w;
>      double* __x_location;
>      double x;

As far as I can tell, the "a" class meets all of the requirements for a
"Pod-struct" laid out in    9/4. And while an access level declaration
does allow the compiler greater latitude in ordering that class's
members in memory, there are no requirements that a Pod-struct's
members be in any particular order. So I would conclude that class "a"
is a Pod-struct.

> A legal layout for 'c' is
>     int w;
>     double* __x_location;
>     int y;
>     double* __z_location;
>     double x;
>     double z;

A Pod-struct could certainly not be laid out this way. I'm also
somewhat skeptical that even a non-Pod struct would be permitted this
much license.

At any rate, I think the kind of layout adjustments that the Standard
has in mind are far less dramatic. For example inserting a vtable
pointer at the beginning a non-Pod object is a fairly common technique
among C++ compilers to implement polymorphic behavior. As an example,
assume that class "a" had a derived class that was not a Pod-struct
(due to a a user-declared destructor):

     struct b: public a
     {
         virtual ~b() {}
     };

With many C++ compilers, each instance of b would incorporate a pointer
to a class vtable as its very first field. And b's class "a" subobject
would come after only this pointer. Therefore converting a "b" pointer
to an "a" pointer (in either direction) would require adjusting the
pointer's value to point to either b's vtable pointer or to the "a"
object (or sub-object) directly.

Greg


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Martin Bonner" <martinfrompi@yahoo.co.uk>
Date: Wed, 20 Sep 2006 09:36:51 CST
Raw View
Greg Herlihy wrote:
> wade@stoner.com wrote:
> >   class a { public: int w; protected: double x; };
> >   class b { public: int y; protected: double z; };
> >   class c: public a, b {};
> >
> > 'a' is not pod (because of protected:) so I believe a legal layout for
> > 'a' is
>
> As far as I can tell, the "a" class meets all of the requirements for a
> "Pod-struct" laid out in    9/4.

"A pod-struct is an aggregate class" (9.4)
"An aggregate is an array or class with .... no private or protected
non-static data members". (8.5.1)

> A Pod-struct could certainly not be laid out this way.
Agreed.

> I'm also
> somewhat skeptical that even a non-Pod struct would be permitted this
> much license.
Why?  What requirement of the standard would if violate?

> At any rate, I think the kind of layout adjustments that the Standard
> has in mind are far less dramatic. For example inserting a vtable
> pointer at the beginning a non-Pod object ...
Agreed! (but that doesn't mean a compiler writer couldn't use such
latitude in future).


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Wed, 20 Sep 2006 16:46:15 GMT
Raw View
Greg Herlihy ha scritto:
>> 'a' is not pod (because of protected:) so I believe a legal layout for
>> 'a' is
>>
>>      int w;
>>      double* __x_location;
>>      double x;
>=20
> As far as I can tell, the "a" class meets all of the requirements for a
> "Pod-struct" laid out in =A79/4. And while an access level declaration
> does allow the compiler greater latitude in ordering that class's
> members in memory, there are no requirements that a Pod-struct's
> members be in any particular order. So I would conclude that class "a"
> is a Pod-struct.
>=20
>> A legal layout for 'c' is
>>     int w;
>>     double* __x_location;
>>     int y;
>>     double* __z_location;
>>     double x;
>>     double z;
>=20
> A Pod-struct could certainly not be laid out this way. I'm also
> somewhat skeptical that even a non-Pod struct would be permitted this
> much license.

I agree with Greg. "a" is a POD-struct according to =A79/4 and so it *is*=
=20
a POD according to =A73.9/10, despite the presence of the access=20
specifier. That said, =A71.8/5 guarantees that "An object of POD type=20
(3.9) shall occupy contiguous bytes of storage." I don't think =A710/5=20
can't circumvent that and lay an "a" base-class subobject in a=20
non-contiguous way. Moreover, =A79.2/12, about the effect of=20
access-specifiers on the class layout, only says that the order of the=20
members is unspecified, hinting that they shall remain contiguous except=20
for possible padding introduced by alignment requirements.

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: wade@stoner.com
Date: Wed, 20 Sep 2006 11:46:46 CST
Raw View
Greg Herlihy wrote:

> >  class a { public: int w; protected: double x; };
> >  class b { public: int y; protected: double z; };
> >  class c: public a, b {};


>
> As far as I can tell, the "a" class meets all of the requirements for a
> "Pod-struct" laid out in    9/4.

9/4: "POD-struct is an aggregate"
8.5.1/1 [aggregate has no protected non-static data members]

So "a" is not POD.

> > A legal layout for 'c' is
> >     int w;
> >     double* __x_location;
> >     int y;
> >     double* __z_location;
> >     double x;
> >     double z;
>
> A Pod-struct could certainly not be laid out this way. I'm also
> somewhat skeptical that even a non-Pod struct would be permitted this
> much license.

Actually, I think the compiler can't take this much license with my
classes, because they don't have a non-trivial default constructor
(12.1/5) meaning the compiler won't get a chance to initialize
__x_location.  In other words, for classes with a trivial constructor,
the object lifetime begins as soon as space is allocated (perhaps with
malloc()).

However, give 'a', and 'b' non-trivial constructors and the license
seems to be there.  In particular, 1.8/5 says that POD objects and
most-derived objects occupy contiguous bytes of storage.  There is a
very strong implication that objects which are neither pod nor
most-derived do not need to be contiguous.  This is commonly the case
when virtual inheritance is involved, but I don't see any indication
that is the only allowed case.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Wed, 20 Sep 2006 17:07:07 GMT
Raw View
Alberto Ganesh Barbati ha scritto:
> I agree with Greg. "a" is a POD-struct according to =A79/4 and so it *i=
s*=20
> a POD according to =A73.9/10, despite the presence of the access=20
> specifier.

As other posters have remarked in this thread, "a" is not a POD-struct=20
(because of the protected access specifier). Therefore my statement is=20
plain wrong. I apologize for the noise.

Ganesh

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]