C/C++ Low Level Curriculum Part 12: Multiple Inheritance

Original Author: Alex Darby

Hello, and welcome to the 12th part of the C / C++ low level curriculum. Really soon after part 11! (No, of course part 11 didn’t get too big and need to be split. Why would you ask?)

Last time we looked at the basics of how inheritance was implemented at the low level; and this time we’re going to examine how using multiple inheritance affects this picture (note: we’re leaving the keyword virtual til next time).

Before We Begin

I will assume that you have already read the previous posts in the series, but I will also put in-line links to any important terms or concepts that you might need to know about to make sense of what you’re reading. I’m helpful like that.

Another big assumption I’m going to make is that you’re already very familiar with the language features of C++ and  comfortable using the language features we’re discussing. If I need to demonstrate anything out of the ordinary I’ll explain it – or at least link to an explanation.

In this series I discuss what happens with vanilla unoptimised win32 debug code generated by the VS 2010 compiler – whilst the specifics will differ on other platforms (and probably with other compilers) the general sweep of the code should be basically the same – because it’s assembly that has been generated by a C++ compiler – and so following the same examples given here with a source / disassembly debugger on your platform of choice should provide you with the same insights we get here.

With this in mind, in case you missed them, here are the backlinks to the previous posts in the series:

  1. /2011/11/09/a-low-level-curriculum-for-c-and-c/
  2. /2011/11/24/c-c-low-level-curriculum-part-2-data-types/
  3. /2011/12/14/c-c-low-level-curriculum-part-3-the-stack/
  4. /2011/12/24/c-c-low-level-curriculum-part-4-more-stack/
  5. /2012/02/07/c-c-low-level-curriculum-part-5-even-more-stack/
  6. /2012/03/07/c-c-low-level-curriculum-part-6-conditionals/
  7. lovingly zipped up a hand-crafted VS2010 solution / project / source code combo to go with this sample which contains the following code:
    1
     
      2
     
      3
     
      4
     
      5
     
      6
     
      7
     
      8
     
      9
     
      10
     
      11
     
      12
     
      13
     
      14
     
      15
     
      16
     
      17
     
      18
     
      19
     
      20
     
      21
     
      22
     
      23
     
      24
     
      25
     
      26
     
      27
     
      28
     
      29
     
      30
     
      31
     
      32
     
      33
     
      34
     
      35
     
      36
     
      37
     
      38
     
      39
     
      40
     
      41
     
      42
     
      43
     
      44
     
      45
     
      46
     
      47
     
      48
     
      49
     
      50
     
      51
     
      52
     
      53
     
      54
     
      55
     
      56
     
      57
     
      58
     
      59
     
      60
     
      61
     
      62
     
      63
     
      64
     
      
    class CTestBaseOne
     
      {
     
      public:
     
          int _iA;
     
          int _iB;
     
       
     
          CTestBaseOne( int iA, int iB )
     
          : _iA( iA )
     
          , _iB( iB )
     
          {}
     
       
     
          int SumBase( void )
     
          {
     
              return _iA + _iB;
     
          }
     
      };
     
       
     
      class CTestBaseTwo
     
      {
     
      public:
     
          int _iC;
     
          int _iD;
     
       
     
          CTestBaseTwo( int iC, int iD )
     
          : _iC( iC )
     
          , _iD( iD )
     
          {}
     
       
     
          int SumBaseTwo( void )
     
          {
     
              return _iC + _iD;
     
          }
     
      };
     
       
     
      class CTestDerived
     
      : public CTestBaseOne
     
      , public CTestBaseTwo
     
      {
     
      public:
     
          int _iE;
     
          int _iF;
     
       
     
          CTestDerived( int iA, int iB, int iC, int iD )
     
          : CTestBaseOne ( iA, iB )
     
          , CTestBaseTwo ( iC, iD )
     
          , _iE ( iB )
     
          , _iF ( iD )
     
          {}
     
       
     
          int SumDerived( void )
     
          {
     
              return return SumBase() + SumBaseTwo() +_iE + _iF;
     
          }
     
      };
     
       
     
      int main( int argc, char* argv[] )
     
      {
     
          CTestBaseOne    cTestBaseOne( argc, argc + 1 );
     
          CTestBaseTwo    cTestBaseTwo( argc, argc + 1 );
     
          CTestDerived    cTestDerived( argc, argc + 1, argc + 2, argc + 3 );
     
       
     
          return      cTestBaseOne.SumBase()  + cTestBaseTwo.SumBaseTwo() 
     
                  +   cTestDerived.SumBase()  + cTestDerived.SumBaseTwo() + cTestDerived.SumDerived();
     
      }

    Once you’ve unzipped it, go ahead and build it.

    Don’t forget to pay attention to the build output – it shows the memory layout which we’re going to talk about next.

     

    Memory Layout

    As you can see, we now have two base classes, and one class that derives from both of them.

    When you build the project, you should see that the memory layout of these classes looks like this:

    1>  class CTestBaseOne	size(8):
     
      1>  	+---
     
      1>   0	| _iA
     
      1>   4	| _iB
     
      1>  	+---
     
      1>  
     
      1>  class CTestBaseTwo	size(8):
     
      1>  	+---
     
      1>   0	| _iC
     
      1>   4	| _iD
     
      1>  	+---
     
      1>   
     
      1>  class CTestDerived	size(24):
     
      1>  	+---
     
      1>  	| +--- (base class CTestBaseOne)
     
      1>   0	| | _iA
     
      1>   4	| | _iB
     
      1>  	| +---
     
      1>  	| +--- (base class CTestBaseTwo)
     
      1>   8	| | _iC
     
      1>  12	| | _iD
     
      1>  	| +---
     
      1>  16	| _iE
     
      1>  20	| _iF
     
      1>  	+---

    This is all as we might expect – given what we found out last time.

    In particular note that:

    • the memory layout of both base classes is embedded into CTestDerived
    • CTestBaseOne and CTestBaseTwo appear in the memory layout in the same order they are declared in the base-specifier-list of CTestDerived.

    n.b. the base-specifier-list is the part of the declaration of a class where the base classes are specified.

    In the simple case of single inheritance we considered in the last post, we saw that the functions of a base class B could be called on instances of a derived class D because:

    • the memory layout of D contains a literal instance of B at an offset of 0 bytes within itself and…
    • …this means that the member data of an instance of B is at the same offset relative to the memory layout of an instance of D
    • …and so the hard coded offsets used to access these members within functions belonging to B are also valid for instances of D

    Looking at the memory layout for this multiply inherited class we can see that:

    1. this relationship still holds for CTestBaseOne and CTestDerived – CTestBaseOne is an an offset of 0 bytes within the memory layout of CTestDerived
    2. however, this same relationship is not true of CTestBaseTwo and CTestDerived

    Given this situation, how do functions of CTestBaseTwo work with instances of CTestDerived?

    As usual the best thing to do do is take a look…

     

    Calling a function of CTestBaseTwo on CTestDerived

    Put a breakpoint on the return statement from main(), run the code, and when it stops right click then choose ‘Go To Disassembly’.

    Rather than paste the disassembly as text this time, I’ve inserted a screenshot of my debugger window – this allows more formatting and highlighting options.

    N.B. in this screenshot I have “Show symbol names” checked under viewing options. Whilst this typically makes it easier to relate disassembly to C or C++ code, it does hide detail (i.e. the addresses of the symbols) .

    CCPPLLC_12Inheritance_P2_MultipleInheritance_00

    Let’s pick this apart then, starting at the current line indicator where the breakpoint is and working down:

    • we can see that (following the x86 thiscall convention) before each function is called, the address of the corresponding object is stored into ecx using lea.
    • First it loads the address of cTestDerived into ecx and then calls CTestDerived::SumDerived()
    • then it…
    • Oh, wait… it’s loading the address [ebp-20h] into ecx…
    • that symbol isn’t resolving in the disassembly window, so what witchcraft is this!?

    I have helpfully highlighted the most salient areas of the screenshot with red boxes 🙂

    If you look at the function calls made in the disassembly, and compare them to the calls in the C++ code, you will see that all of the high level function calls have an analogue at the assembly level except for cDerived.SumBaseTwo().

    CTestBaseTwo::SumBaseTwo is getting called, but with [ebp-20h] as the this pointer in ecx, not [cTestDerived] (n.b. see the top red box in the screenshot).

    So, the question is: how does the address [ebp-20h] related to the address of cTestDerived?

    This would be a good time to reiterate that the watch window is your friend. We can use the watch window to Sherlock Holmes our way to an answer.

    If you look in the watch window below the disassembly view (shown again below by itself for those of you who are vertical resolution challenged) you can see that I have used watch window expression evaluation to find out some information about these values:

    CCPPLLC_12Inheritance_P2_MultipleInheritance_WatchCasting_00

    This shows us that:

    • the address of cTestDerived is 0x0048fa84…
    • … and the address of cTestDerived cast to a pointer to CTestBaseOne has the same address, …
    • …but when the address of cTestDerived is cast to CTestBaseTwo we get 0x0048fa8c…
    • …which is the same value as [ebp-20h]…
    • …or an 8 byte offset from the address of cTestDerived…
    • …which is the offset of CTestBaseTwo within CTestDerived

     

    Should this be surprising?

    Here’s the memory layout of CTestDerived again:

    1>  class CTestDerived	size(24):
     
      1>  	+---
     
      1>  	| +--- (base class CTestBaseOne)
     
      1>   0	| | _iA
     
      1>   4	| | _iB
     
      1>  	| +---
     
      1>  	| +--- (base class CTestBaseTwo)
     
      1>   8	| | _iC
     
      1>  12	| | _iD
     
      1>  	| +---
     
      1>  16	| _iE
     
      1>  20	| _iF
     
      1>  	+---

    Since we know that:

    • (within non-static member functions) member variables are accessed via constant offsets from their this pointer
    • the memory for CTestBaseTwo starts at an offset of 8 bytes from the start of the memory layout of an instance of CTestDerived

    it follows that CTestBaseTwo::SumBaseTwo() wouldn’t work if the compiler passed the address of an instance of CTestDerived because the constant offsets used to access the members of CTestBaseTwo would be off by 8 bytes.

    Consequently, any time a CTestBaseTwo member function is called on an instance of CTestDerived the compiler must ensure that a compatible this pointer is generated to pass to the function – i.e. pointing at the start address of CTestBaseTwo within the instance of CTestDerived.

    Frighteningly obvious once you know isn’t it?

    I honestly don’t think it should be surprising though – given the way that we know data within user defined types is accessed at the assembly level (see part 10), it pretty much had to work like this.

     

    …one more little thing

    In the example above, cTestDerived is a Stack Frame.

    This means that the compiler can calculate the address of the instance of CTestBaseTwo within cTestDerived at compile time, and can therefore access it at no extra cost compared to any other Stack variable.

    We should probably check whether this is this any different when we’re dealing with a pointer to a CTestDerived at an arbitrary point in memory, just to be thorough.

    Luckily I have already thought of this 🙂

    If you place a breakpoint on the return statement of CTestDerived::SumDerived  you can check the disassembly yourself, but here are the relevant lines from my disassembly window:

    1
     
      2
     
      3
     
      4
     
      5
     
      6
     
      7
     
      8
     
      
       52:     int SumDerived( void )
     
          53:     {
     
      001010A0  push        esi  
     
      001010A1  mov         esi,ecx  
     
      001010A3  push        edi  
     
          54:         return SumBase() + SumBaseTwo() +_iE + _iF;
     
      001010A4  lea         ecx,[esi+8]  
     
      001010A7  call        CTestBaseTwo::SumBaseTwo (101050h)

    As you should be able to see by now, the code in this function is adding a constant offset of 8 bytes onto the this pointer it is passed to generate the this pointer it is passing to CTestBaseTwo::SumBaseTwo

    If you’re having trouble seeing it, remember that the ‘thiscall‘ win32 member function calling convention uses ecx to pass the this pointer.

    Most significantly, looking back to the last post, we can see that this is essentially the same way that member variables of user defined types are accessed when we had a pointer to an instance of  a user defined type – in fact, at the level of the assembly codethere is really no difference between a member variable and a base class; this distinction is really only meaningful at the level of the C++ code.

    We now also know that multiple inheritance can cause your code a small additional cost in pointer arithmetic when calling member functions of any of its base types that has a non-zero offset within its memory layout.

     

    What was that earlier? about declaration order?

    If you’re paying attention, you should have noticed that when we looked at the memory layout of CTestDerived I mentioned in passing that the ordering of  CTestBaseOne and CTestBaseTwo within it matches the textual order they were listed in its base-specifier-list.

    This is obviously significant, since it implies that if the textual order in which CTestBaseOne and CTestBaseTwo are listed changes, then the memory layout of CTestDerived will change to reflect this.

    If you swap the order of CTestBaseOne and CTestBaseTwo around here’s the memory layout printed during the build process:

    1>  class CTestDerived	size(24):
     
      1>  	+---
     
      1>  	| +--- (base class CTestBaseTwo)
     
      1>   0	| | _iC
     
      1>   4	| | _iD
     
      1>  	| +---
     
      1>  	| +--- (base class CTestBaseOne)
     
      1>   8	| | _iA
     
      1>  12	| | _iB
     
      1>  	| +---
     
      1>  16	| _iE
     
      1>  20	| _iF
     
      1>  	+---
     
      1>

    Given what we have discovered so far, we can see that this new memory layout means that CTestDerived can now be treated as an instance of CTestBaseTwo.

    We can also see that with this new layout, the compiler would need to adjust CTestDerived pointers in order to call CTestOne functions.

    I leave it as an exercise for you, o budding expert reader of x86 disassembly, to check this for yourself 🙂

     

    Aside: construction and destruction with single inheritance

    Something we entirely skipped past in last post was construction and destruction of inherited types.

    This was intentional – construction and destruction behaviour is straightforward with single inheritance.

    We all should know the expected high level behaviour for single inheritance (of arbitrary depth) – in summary:

    • each constructor calls the constructor of its base class before it does the work of its own function definition – i.e. classes are constructed in order ”from inside to out” or “least to most derived“.
    • destructors do the opposite, each destructor does its own work before calling the destructor of its base class – i.e. classes are destructed in order “from outside to in” or “most to least derived“.

    The disassembly matches the high level behaviour in a very straightforward way and I leave it as an exercise for the reader to step through the disassembly of construction & destruction in some test code to see this in action.

    Like the rest of the behaviour we’ve discovered so far, when you think about it, it’s actually pretty obvious that this sort of ‘stack-like’ construction / destruction behaviour is required in order to make inheritance work correctly.

     

    Construction and destruction with multiple inheritance

    It was pretty obvious that we were coming to this, right?

    What happens with construction and destruction when multiple inheritance is involved is less simple.

    For example, what order do the constructors of multiple base classes get called in? … and what order do their destructors get called in?

    We also assume that – since the constructor and destructor are member functions – there must be some fiddling with this pointers during this process too.

    Luckily, this is very easy to empirically determine: we can just add some text output into the constructors and destructors of the sample classes to print the name of the function and the value of their this pointer.

    Here’s a link to a VS2010 project I prepared earlier to do just that, I’ve just added a little extra code to the original example code.

    Below is the command line output produced when it is run:

    CCPPLLC_12Inheritance_P2_ConDestructionThisPointerFixing00

    You can see that:

    • constructors are called in the textual order they appear in the class declaration for CTestDerived – from least derived (i.e. CTestBaseOne) to most (CTestDerived).
    • destructors are called in the opposite order – this is to ensure that work done in the constructors is un-done in the opposite order.
    • this also shows that the this pointers are changed for the constructor and destructor of CTestBaseTwo just as they did when we were calling regular member functions

    At this point you should feel free to swap around the order of CTestBaseOne and CTestBaseTwo in CTestDerived‘s base-specifier-list to check that construction and destruction follow the same rules as the ordering of base types in derived type’s memory layout (they do, I promise).

     

    Summary

    That’s it for this time and it was massive! I bet you’re glad I split this off from post 11 now 🙂

    The astute amongst you will have noticed that we have not looked at any code using the keyword virtual. This is entirely deliberate, and that’s for next time.

    So, let’s recap what we’ve discovered so far about inheritance…

    First, what we learned about single inheritance in part 11:

    1) We know that the memory layout of user defined types is fixed at compile time…

    2) …and so code accessing a data member of a user defined type can use a constant offset relative to the start address of an instance of the type (see part 10).

    3) In single inheritance, the memory layout of a derived type D literally extends that of its base type B.

    4) This ensures that the inherited members of B are at the same constant offsets relative to the start address of an instance of D as they would be relative to the start address of an instance of B

    5) …which means that a pointer to an instance of type D can safely be treated as a pointer to an instance of type B

    6) …which in turn guarantees that member functions of type B can safely be called on instances of type D.

     

    We’ve also discovered that if a derived class D class inherits from multiple base types A and B, then this multiple inheritance breaks the convenience of the single inheritance approach somewhat:

    7) As with single inheritance, the memory layout of an instance of D contains the member data of both A and B, laid out exactly as it was in each base class.

    8) Member functions of both type A and type B will use constant offsets relative to the their this pointers to access their data members.

    9) Logically; only either A or B may have an offset of 0 bytes within the memory layout of an instance of D

    10) … consequently a pointer to an instance of type D can only be safely treated as a pointer to whichever of A or B has a 0 byte offset within its memory layout

    11) Which base type has a 0-byte offset is determined by the textual ordering of the A and B types within the base-specifier-list of D‘s class declaration

    12) …if A were at the 0 byte offset within D, the compiler would need to calculate a compatible ‘this’ pointer whenever a member function of B called on an instance of D (and vice versa)

    13) …when an instance of D is created, the instances of A and B contained within its memory layout will be constructed by their own constructors before the constructor for D is called, and…

    14) …the order in which A and B are constructed depends on their textual ordering within the base-specifier-list in D‘s class declaration (i.e. they will be constructed in memory offset order).

     

    Disclaimer

    The above numbered bullet points are facts we have discovered empirically by examining the behaviour of win32 x86 code created by the Visual Studio 2010 compiler.

    Do not assume that code generated by other platforms / compilers will behave identically. It should behave very similarly, but you should check.

    POD type you should be able to save out its memory to file as binary and load it back into the memory of a different instance of the same type.

    iff you don’t change target platform, compiler, compiler options, alignment specifications, or the declaration of the type.

    Thanks

    Thanks for peer review go out to Bruce Dawson and Amir Embrahimi; and for general #altdevblogaday admin assistance to Luke Dicken.

     

    Appendix: What does the C++ standard have to say about all this?

    I spent some time reading the C++11 ISO standard (or a near final revision of it at least), but even after consulting the source it is not 100% clear to me exactly what is and what isn’t guaranteed by the standard – see the below for more information.

    this near-final draft of the ISO C++ 11 standard document  when I was looking up various bits for this post (you have to pay ANSI for the actual one!).

    If you want more information on any of the points below, click the link above to download the .pdf and search for the indented text – that will get you to the page it was on. This document does not make for light reading!

     

    1. Ordering of base classes in memory within a multiply inherited class.

    As far as I can tell, this is not guaranteed by the standard – in fact the draft standard says this:

    10.1 Multiple base classes [class.mi]

    1 A class can be derived from any number of base classes. [Note: The use of more than one direct base class

    is often called multiple inheritance. — end note ] [Example:

    class A { /∗ … ∗/ };

    class B { /∗ … ∗/ };

    class C { /∗ … ∗/ };

    class D : public A, public B, public C { /∗ … ∗/ };

    — end example ]

    2 [Note: The order of derivation is not significant except as specified by the semantics of initialization by

    constructor (12.6.2), cleanup (12.4), and storage layout (9.2, 11.1). — end note ]

    which more or less says that it’s not guaranteed.

     

    2. Ordering of data members within a class.

    So, it appears that a C++ compiler is allowed to reorder data members of a class in memory vs. their textual declaration order if (and only if) their access control (i.e. public, private, protected) is different:

    15 Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (11). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other;

    I can’t imagine this would ever be a problem for you unless you’re writing a reflection library or similar.

     

    3. Ordering of constructor calls when constructing types with base types

    Thankfully, there does appear to be some sanity remaining in the universe; as I managed to find the part of the standard that specifies the order in which constructors are called for types that use inheritance:

    In a non-delegating constructor, initialization proceeds in the following order:

    — First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

    — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

    — Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

    — Finally, the compound-statement of the constructor body is executed.

    [Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the

    reverse order of initialization. — end note ]

    TL;DR – (if you are not using virtual base classes) each constructor initialises its base classes in declaration order, then the class members in declaration order, then the constructor’s body is executed called.

     

Life can be better (part 2 of 3)

Original Author: Amir Ebrahimi

mind.

NOTE: Please consult with a health professional before making any changes with your own health. I am certainly not a doctor and will assume that you are an adult who will ultimately be responsible for his or her own health. I’ve done my best to portray this post as personal truth and not accepted science. I realize that every person’s body is different and therefore may respond differently to a specific health regimen.

Background

I grew up playing role-playing games (RPGs) like other hackers, geeks, nerds, and escapists out there. However, fantastical worlds like that of Dungeons & Dragons didn’t grab my interest as much as sci-fi did. Although I remember getting lost in the dark, gritty world of Shadowrun on my Super Nintendo (based on the RPG), for some reason I chose Cyberpunk 2.0.2.0. (a different RPG) when it came time to run a campaign. I loved the idea of a futuristic world where man and machine could meld. Through Cyberpunk, I became acquainted with the use of the term “meat,” crassly used to describe the human body. “Cyberspace” was the place where netrunners existed, while their “meat” resided in “meat-space,” otherwise known as the physical world. Essentially, a netrunner could bring consciousness into an alternate world without reliance on the body.

I connected with Cyberpunk as a teenager mainly because of my growing interest in computers. As I tried to figure things out with computers, I found that my mind gravitated towards combing through my thoughts to better process them, as a memory manager might do to defragment allocations. I also found that I was entertained simply with thought itself, traversing different paths to see where my mind would end up. I realize that these behaviors are what primarily distinguish introversion from extroversion and as a result, believe that they lend the identification of self to the thoughts and processing of the brain. Instead of “I am what I can do” it becomes “I am what I can think”. I also think that those same behaviors help us become better software engineers. Even though I enjoyed skateboarding, football, baseball, paintball, and other physical activities, I somehow managed early on to form a mental model where the brain/mind and body had little, if nothing at all, to do with each other.

Oddly enough, my naivety around health later in life didn’t stray far from that teenage fascination with cyber-augmented posthumanism. In the last article, I mentioned that after starting to work out w/ co-workers at lunch, I was able to get into the best physical shape that I had been in since high school football (hey, in Alabama, we did two-a-days). Unfortunately, even with having increased strength, my energy, mood, and mental health were declining. At age 25, I thought that health had more to do with the way I looked than how I felt. In all honesty, I’d rather have a sexy mind rather than trying to look sexy. Well, during the summer of 2005, in the midst of my third extended crunch for a console game, I finally hit rock bottom and decided that I needed help.

Depression

I used to think that it was shameful to talk about depression and/or any mental impairment. I believed that this was one thing that I was supposed to figure out on my own. In my judgment, sitting with shame around depression let me run circles around questions of “Why?”, rather than looking at the “What?”. As I wrote in my previous article, I did notice the warning signs of feeling chronically tired, feeling “heavy” to move around even though I wasn’t grossly overweight, and starting to think that most things I had to get done were weighty tasks. For me, this was a dramatic change from how I remember feeling when I got my first internship in the industry. I went to a general practitioner for a check up and when the blood work came back inconclusive I decided that I just had to push on. I continued that way until things got worse and I didn’t know what else to do, so I finally decided to see a psychologist.

depression is caused by a combination of genetic, biological, environmental, and psychological factors”. In other words, we don’t quite know the causes. Trying to answer those questions of “Why do I feel this way?” or “How did I come to this place?” resulted in many years of sitting with different psychologists. I think a good psychologist can provide temporary help to calm acute anxiety or depression with talk-therapy, but dialogue is less useful at resolving any root physiological cause(s) of emotional disturbance when they exist. While I’ll agree that psychotherapy has its own benefit to healing emotional wounds and looking at long-standing issues, on a practical level of my day-to-day experience it didn’t provide the answers.

different ways for different people. Separate from major health problems, I have seen stress have impact in minor ways, too, such as frequent irritability or negativity, relationship problems, or motivational challenges to name a few. What I can say is that, at the time I experienced depression, I was working more (including weekends), sleeping less, had little time to socialize, and eating outside for most of my meals if not skipping them altogether. My worst night was working until 6 am on a build that we had to send off to magazine reviewers and being asked to come back in around 10 am. Most crunches I experienced at different companies from 2003-2008 lasted for more than 4 months out of the year. Even though there was some time off and a slower pace following the release of a game, somehow my batteries were not getting recharged.

Moving past the shame allowed me to see the questions of “What can I do?”. Well, in parallel with psychotherapy, I also met with a psychiatrist to hear another point of view. I worked through different SSRIs, SNRIs, and anti-anxiety medications; battling different side-effects in an effort to find the “right one for me”. My judgment of these drugs are that they can work as a crutch, but in the same way that caffeine can keep me operating out of touch with my natural energy levels. The drugs provided relief and got me back on my feet, however, in the end they pale in comparison to my current experience at a holistic level.

When I experienced depression, it was damn near impossible to distinguish that I was not my thoughts. At work, I was unhappy with most of what I was tasked with doing, irritable with requests from others, not motivated to get my work done, and negatively thinking about what the company was doing and the manner in which we were doing it. Now, I’m not saying that some form of each of those thoughts/feelings/behaviors aren’t welcome in order to alert me to doing or suggesting something better. However, preponderance of these thoughts/feelings/behaviors as my M.O. led me to believe that I am a negative, unhappy, and unmotivated person. My invitation to you if you’re in that space: don’t draw conclusions there. From my experience, I can attribute more of the ways I was thinking at that point in my life to my overall physical health.

After experiencing a gradual decline in my state of being over the years, I realize now what negligence towards health in the face of stress has afforded me. I also carry deep concern for any others that, like me, are/were not as well equipped to deal with stress. As an employer, I think it is ever important to protect our employees from burnout. In the process of learning about my own health, I’ve come to a rudimentary understanding of how stress works in the body.

Stress

The PAT (pituitary-adrenal-thyroid) axis is an important system that regulates the hormones in the body in order to keep the body in balance. I think of them as good friends who have my back during good and bad times (regulators, mount up!). When stress comes and goes, each gland does their part. Everything I encounter in the day impacts my PAT axis from my alarm clock in the morning to the traffic on the way to work to the tasks I’m trying to complete on any given day. Additionally, how I choose to react to those stressors can also tax my system. All of these stressors deplete the stores of hormones and endorphins in my body, which is why I’m sometimes exhausted by the end of the day and not able to handle much more. The food I eat helps replenish what has been used after being digested and synthesized into what the body needs. However, under chronic stress the body is producing elevated and continued levels of hormones and endorphins in an attempt to keep the body in balance. Unfortunately, the immune and digestive systems are suppressed, among other things that are affected, which can lead to a non-optimal state for both energy absorption and perception of well-being.

I mentioned perception in the previous article because I wanted to allude to the possibility of being stuck in a fearful, anxious, doubtful, exhausted, etc. state that elevated stress levels can help bring about. To put this in perspective, I consider what happens when adrenaline rushes through my body and how much my thinking can change in the moment. I’ve experienced this while driving when I am in a happy, easy-going mood and with a flash of a potentially dangerous situation with another car I have both a physical and emotional/mental reaction. The world I was seeing as beautiful only moments ago has now become “out to get me.” In a similar way, I see elevated levels of stress having effects on my perception of how I’m performing, the relevance or efficacy of what I’m working on, how others are doing, and so on.

Beyond Depression

Even though I got back on my feet eventually, I somehow never felt as good as I did when I entered the industry. I no longer felt terribly bad, but I didn’t feel energized or great either. Unrelated to energy levels, stress, depression, or any other things I’ve spoken to already, about a year and a half ago I had started working with a nutritionist in preparation for a surgery. The belief was that I would have a quicker recovery from the surgery if I was in a healthier state. So, laughably now, I considered “getting healthy” as something I’d do for a short while up until the surgery. Gradually, I changed my diet, started drinking more water (which was up from almost none at all), reduced my caffeine intake, took tailored supplements and started to feel radically different in the first three months. I think it is more a testament to the shoddy state I was in more than any one thing that I was doing in particular. I started noticing that when I woke up I had energy to boot and was ready to take on the day. I also noticed that my brain function seemed to change. I no longer would get stuck worrying about something incessantly. My brain processing was becoming razor sharp again and my focus improved. When I started to feel the anxiety that I carried around ease up and become more manageable, I became dumbfounded. I realized only after feeling much better that the one question I recall none of the health professionals asking me from 2005 all the way up until 2011: what was I actually eating?

Food for Thought (and Energy!)

If I try to remember what my meals looked like when I started working professionally in 2003 (and to some extent all the way back to 1999 at GaTech) up until a year and a half ago:

Breakfast

Cereal w/ milk, muffin, or bagel w/ peanut butter or almond butter; pancakes or eggs, bacon on the weekends

Lunch

Usually Mexican/Indian/Thai food (varied over the years depending on where I was working), burger w/ fries, occasional salad, sandwich with chips

Dinner

If working late, then whatever food was brought in if the company catered; otherwise, whatever food was close around (likely the same places I ate at during lunch); or skipping dinner and eating some kind of snack at home later in the evening (usually another bowl of cereal or PBJ or whatever could be made quick)

When not working late – frozen pizzas or pre-packaged food that could be warmed up (sometimes in microwave, sometimes in oven, sometimes in saucepan); pasta w/ tomato sauce; mac and cheese; thai/indian take-out

Fluids

Orange juice in the morning

Coffee many times throughout the day, which also killed my appetite

Very little water if none at all (would drink water during workout sessions)

Occasional soda

Certainly anyone can look at this and say, yeah, that doesn’t look like the healthiest diet, but at first glance I wouldn’t think someone would say there was anything particularly wrong with it either. However, there is one thing that is missing in significant quantity – vegetables. There would rarely be any sort of vegetable or green on my plate unless it snuck onto the plate (luckily, Thai or Indian food usually has vegetables).

Fast forward to today and I now consume the following:

Before breakfast

10 oz. of carrot juice (used to buy this in the store and then decided to simply buy my own 5 lb bags for the week and get a juicer); I recently started juicing the leftover stalks of whatever green I’ve been eating in addition to the carrot juice

Breakfast

Two eggs, parsnips w/ cinnamon or seasoned cauliflower / rutabagas w/ diced onions + some sort of green sauteed in butter (chard, spinach, kale, or collard), two slices of toast

Before lunch

I usually try to drink 1-2 quarts of water before lunch. I have a stainless steel water bottle that is close to a quart that I keep filled at my desk. I don’t usually have any liquids when I’m eating a meal to aid in digestion. I’ll drink something before or an hour after my meal.

Lunch

Usually, this is some form of leftover from dinner the previous night(s) that I bring to work and warm up in a toaster oven. Occasionally, I eat something from around the office, but this was difficult initially because I find that most places don’t include fresh vegetables or greens with a good sized portion of protein

Dinner

  • Two small lamb loin chops (pan-fried, then broiled) w/ brussel sprouts (sauteed)

  • Ground lamb and sweet potato (steamed and mashed w/ butter) tacos w/ onions, garlic, and chard, collard greens, or kale (sauteed) in a brown rice or corn tortilla + additional sweet potato, onions, garlic, and greens on the side

  • Turkey burger w/ broccoli, cauliflower, beets (both gold and purple), or whatever else I have left in the fridge

  • Seasoned, baked chicken breast w/ blanched and then sauteed green beans

  • Turkey meatloaf w/ kale chips, baked cauliflower or turnips/rutabagas

Miscellany

  • Occasionally, I mix whole grains in: brown rice, quinoa, millet

  • I’ll eat fish and beef occasionally

  • Dairy products come and go in my diet and when I do eat them I go for the whole fat, raw versions when available (or at least vat or low-heat pasteurized)

  • I’ll have fruits occasionally as a dessert or a snack

All of these meals are makeable in about 30 minutes. When I am eating later than I like or have to run to Whole Foods to pick up groceries, then I’ll usually grab stuff from the hot food bar — again, loading up on vegetables; including ones that I don’t buy regularly, such as bok choy.

The key here is that I eat vegetables now in significant quantity due to the mix of vitamins and minerals present. Two-thirds of my plate will be vegetables and only a third will be a hand-sized amount of protein/fat (some vitamins that come from vegetables need fat to be absorbed) and occasionally some starch such as brown rice or quinoa. If I’m eating out somewhere, I’ll usually request for them to double whatever vegetables come on my plate.

My cupboard is bare for the most part – no more cereals, potato chips, dry pastas, crackers, etc.

My fridge is full of organic vegetables and meat.

sugar.

I cook with butter usually for breakfast and olive oil (on low/med heat; there are better oils for high heat) for all other meals.

I drink lots of water (3 quarts) and usually only water during the day (occasionally a kombucha or decaf tea) — not during meals.

I use a rice-cooker w/ a steam basket to steam most of my vegetables (quicker and easier than the stove top) – I bought one from a Japanese food store

I still enjoy an occasional coffee, sweets, pasta, pizza, etc. from time-to-time, however, the key is that I keep none of that in the house.

My grocery bill for the workweek is roughly $75 with some carry-over to the weekends. The most expensive items are meat, eggs, and carrots (because I’m buying those in 5 lb bags). Vegetables are for the most part cheap in their individual quantities.

I didn’t eat this way before because I considered food to be a nuisance. Even though I had enjoyed great meals in restaurants or cooked by others, I treated that as a luxury. My relationship with food was that I needed to be doing something else other than preparing a meal or taking time to enjoy it calmly. So, when I was hungry, my intention was simply to eat something as quick as possible and get back to what I was doing. One way I could characterize my prior understanding of food is that I could eat anything and produce anything. My new understanding is garbage in == garbage out. Now, that’s not entirely true because I know that I was still able to develop working code under extreme stress even though I was not eating well. However, I also know now that I was not producing at my optimal performance.

maximize the nutrients in my food, not simply because non-organic is “bad” (and yes, I’m aware that the term “organic” is prone to abuse in efforts for companies to make more money). I choose specific foods over others for the same reason. I prepare my food and use whole ingredients because I like knowing what I’m putting into my body.

Summary

certain amino acids and minerals for the optimal functioning of the brain, the glycemic index, or what foods are nutrient rich. However, the most valuable guiding strategy that I have learned from all of this is that nutrition is more about how I feel and less about how I look, which is why I misunderstood and took no interest. I knew that eating healthy was important; however, I had never experienced first-hand the effects, nor did I have a reason to. I think that nutrition is even more important than exercise and that physical activity comes naturally as an effect of having more potential energy in my body. My invitation to you is to find out what works for you. Become the patient observer. Pay attention to how you feel after meals. Notice what improves your moods. Take time to prepare your own food and enjoy it stress-free, so you can maximize the nutrients you are taking into your body. What motivates me to continue is twofold: I don’t want to go back to feeling the way I used to feel and, more importantly, I want to see what’s possible.

I’ll also add that everything isn’t perfect today. I get irritable at times. I wake up on the occasional morning and feel sluggish. I still battle with anxiety. I’m exhausted sometimes at the end of the day. I’m frustrated occasionally with the performance of my own work or with what we’re doing as a team. However, all of those things are blips now where before they were part of my routine, daily experience. Having a programming background, I simply see this as an optimization problem to figure out what can be done better. However, optimizing the human body is a bit more difficult than shaving cycles off of a routine. Maybe in a cyber-augmented posthuman world of the future, we’ll have the equivalent of a software profiler for the human body.

In the next article, I’ll shift focus to the changes I’ve made that impact how work gets done both at a studio and individual level, talk a bit about what I’ve changed in regards to sleep, some practical things I do to conserve willpower throughout the day, and tie up any loose ends with this series.

C/C++ Low Level Curriculum Part 11: Inheritance

Original Author: Alex Darby

Hello, and welcome to the 11th part of the C / C++ low level curriculum. About time? Definitely!

Last time we looked at the basics of User Defined Types: how structs, classes, and unions are laid out in memory; and (some of) the implications of memory alignment on this picture.

In part 11 we’re going to look at how inheritance affects this picture, in particular the implications for memory layout of derived types and also for their behaviour during construction and destruction (note: we’re leaving multiple inheritance and the keyword virtual out of this picture to start with).

 

Before We Begin

I will assume that you have already read the previous posts in the series, but I will also put in-line links to any important terms or concepts that you might need to know about to make sense of what you’re reading. I’m helpful like that.

Another big assumption I’m going to make is that you’re already very familiar with the C++ language and  comfortable using the language features we’re discussing, as well as the accepted usage limitations of those features etc. If I need to demonstrate anything out of the ordinary I’ll explain it – or at least link to an explanation.

In this series I discuss what happens with vanilla unoptimised win32 debug code generated by the VS 2010 compiler – whilst the specifics will differ on other platforms (and probably with other compilers) the general sweep of the code should be basically the same – because it’s assembly that has been generated by a C++ compiler – and so following the same examples given here with a source / disassembly debugger on your platform of choice should provide you with the same insights we get here.

With this in mind, in case you missed them, here are the backlinks to the previous posts in the series:

  1. /2011/11/09/a-low-level-curriculum-for-c-and-c/
  2. /2011/11/24/c-c-low-level-curriculum-part-2-data-types/
  3. /2011/12/14/c-c-low-level-curriculum-part-3-the-stack/
  4. /2011/12/24/c-c-low-level-curriculum-part-4-more-stack/
  5. /2012/02/07/c-c-low-level-curriculum-part-5-even-more-stack/
  6. /2012/03/07/c-c-low-level-curriculum-part-6-conditionals/

I won’t lie – it’s not light reading 🙂

 

Class vs. Struct: a Gentle Reminder

The C++ keywords struct and class define types that are identical in implementational detail and what you can do with them (the only difference being at the language level: the default access specifier if none is specified is private for class, and public for struct).

So, whilst I will be using the keyword class throughout this article please take it as read that anything we talk about here applies equally to types defined using the keyword struct.

 

What happens when we derive from another type?

So, what does happen when you derive a user defined type from another non built-in type?

Clearly the data members you specify in the declarations have to go somewhere, and so do all those specified in the type(s) you are deriving from.

At the level of C++ there is nothing other than the standard to tell you how this works – and nothing other than looking at what happens with the code generated by the compiler you are using will tell you for definite.

As in the last post, we will be relying heavily on the frankly awesome secret 007 compiler flag /d1reportSingleClassLayout in order to tell us exactly how the (Visual Studio 2010 win32 x86) compiler has decided to lay our example structures out in memory.

It’s about time to look at some example code, so, rather than have you go through the usual rigmarole of setting up your project I have kindly set one up for you.

The zip file in this link contains a VS2010 solution with a single project and .cpp file lovingly set up to run the code shown below, which is in 00_Inheritance.cpp

1
 
  2
 
  3
 
  4
 
  5
 
  6
 
  7
 
  8
 
  9
 
  10
 
  11
 
  12
 
  13
 
  14
 
  15
 
  16
 
  17
 
  18
 
  19
 
  
class CTestBase
 
  {
 
  public:
 
      int _iA;
 
      int _iB;
 
  };
 
   
 
  class CTestDerived
 
  : public CTestBase
 
  {
 
  public:
 
      int _iC;
 
      int _iD;
 
  };
 
   
 
  int main(int argc, char* argv[])
 
  {
 
      return 0;
 
  }

When you compile this project you should get the following in your “Build” output window (the magic of /d1reportSingleClassLayout!) :

1> class CTestBase size(8):
 
  1>   +---
 
  1> 0 | _iA
 
  1> 4 | _iB
 
  1>   +---
 
  1> 
 
  1> class CTestDerived size(16):
 
  1>    +---
 
  1>    | +--- (base class CTestBase)
 
  1>  0 | | _iA
 
  1>  4 | | _iB
 
  1>    | +---
 
  1>  8 | _iC
 
  1> 12 | _iD
 
  1>    +---

Looking at this, it should be fairly obvious that the data members of CTestDerived have just been concatenated onto the end of the memory layout of CTestBase – and, more importantly, that the memory layout of CTestBase within CTestDerived is identical to that when it’s not a base class.

It’s that simple!  (for certain definitions of ‘it’ and ‘simple’…)

Armed with this information from last post:

Stack Overflow for more detail of the wording).”

it is obvious that – since CTestDerived inherits all of the members of CTestBase – its members must appear after those of CTestBase in memory.

I remember when I had this explained this to me – not long after having started my first job in the industry as a fresh faced graduate – I did the internal equivalent of a double-take, because the information I had just received was so bleedingly obvious that I couldn’t believe I’d ever not known it.

 

If it’s that easy, why post about it?

Good question!

The fact that the memory layout of a type is identical in all situations is required by the standard – and also by logic – let’s see why…

First, download and open the second zipped VS2010 project file – this contains the code below in 01_InheritanceWithFunctions.cpp:

1
 
  2
 
  3
 
  4
 
  5
 
  6
 
  7
 
  8
 
  9
 
  10
 
  11
 
  12
 
  13
 
  14
 
  15
 
  16
 
  17
 
  18
 
  19
 
  20
 
  21
 
  22
 
  23
 
  24
 
  25
 
  26
 
  27
 
  28
 
  29
 
  30
 
  31
 
  32
 
  33
 
  34
 
  35
 
  36
 
  37
 
  38
 
  39
 
  40
 
  41
 
  42
 
  43
 
  
class CTestBase
 
  {
 
  public:
 
      int _iA;
 
      int _iB;
 
   
 
      CTestBase( int iA, int iB )
 
      : _iA( iA )
 
      , _iB( iB )
 
      {}
 
   
 
      int SumBase( void )
 
      {
 
          return _iA + _iB;
 
      }
 
  };
 
   
 
  class CTestDerived
 
  : public CTestBase
 
  {
 
  public:
 
      int _iC;
 
      int _iD;
 
   
 
      CTestDerived( int iA, int iB, int iC, int iD )
 
      : CTestBase ( iA, iB )
 
      , _iC ( iC )
 
      , _iD ( iD )
 
      {}
 
   
 
      int SumDerived( void )
 
      {
 
          return _iA + _iB + _iC + _iD;
 
      }
 
  };
 
   
 
  int main(int argc, char* argv[])
 
  {
 
      CTestBase       cTestBase   ( argc, argc + 1 );
 
      CTestDerived    cTestDerived( argc, argc + 1, argc + 2, argc + 3 );
 
   
 
      return cTestBase.SumBase() + cTestDerived.SumBase() + cTestDerived.SumDerived();
 
  }

Put a breakpoint on the return statement from main, and then compile and run the release build configuration.

The first thing to note is that the memory layouts printed to the output window during the build are unaffected by the addition of these functions.

This is what you would expect, as we know that non-virtual member function calls are resolved at compile time just like regular non-member and static member functions.

Since CTestDerived is derived from CTestBase, we know from our high level knowledge about C++ that we can call both of these functions on an instance of CTestDerived – what we’re looking at right now is how this is implemented.

When the breakpoint is hit, right click and choose “Go To Disassembly”.

I’ve pasted the part I’d like to discuss below…

(N.B. to get the same disassembly as this you should have the following Viewing Options checked in the disassembly window: ‘Show source code’, ‘Show line numbers’, ‘Show address’, and ‘Show symbol names’)

1
 
  2
 
  3
 
  4
 
  5
 
  6
 
  7
 
  8
 
  9
 
  10
 
  11
 
  
    44:     return cTestBase.SumBase() + cTestDerived.SumBase() + cTestDerived.SumDerived();
 
  0129109A  lea         ecx,[cTestDerived]  
 
  0129109D  call        CTestDerived::SumDerived (1291060h)  
 
  012910A2  lea         ecx,[cTestDerived]  
 
  012910A5  mov         esi,eax  
 
  012910A7  call        CTestBase::SumBase (1291020h)  
 
  012910AC  lea         ecx,[cTestBase]  
 
  012910AF  add         esi,eax  
 
  012910B1  call        CTestBase::SumBase (1291020h)  
 
  012910B6  pop         edi  
 
  012910B7  add         eax,esi

We’ve previously covered that the win32 calling convention for member functions (‘thiscall’) passes this to member functions in the ecx register.

Correspondingly, you’ll notice that the address of cTestBase and cTestDerived are being stored in ecx using lea (‘load effective address’) immediately before calling their member functions.

Specifically, note that the address of cTestDerived is passed un-tampered with in ecx when calling the base class function CTestBase::SumBase. Remember this for later (and for the next post!).

So, let’s look at the disassembly for CTestBase::SumBase and CTestDerived::SumDerived – I tend to single step the disassembly and step into them, but putting breakpoints in them is more reliable 🙂

CTestBase::SumBase

1
 
  2
 
  3
 
  4
 
  5
 
  6
 
  7
 
  
    14:     int SumBase( void )
 
      15:     {
 
      16:         return _iA + _iB;
 
  01291020  mov         eax,dword ptr [ecx+4]  
 
  01291023  add         eax,dword ptr [ecx]  
 
      17:     }
 
  01291025  ret

CTestDerived::SumDerived

1
 
  2
 
  3
 
  4
 
  5
 
  6
 
  7
 
  8
 
  9
 
  
    33:     int SumDerived( void )
 
      34:     {
 
      35:         return _iA + _iB + _iC + _iD;
 
  01291060  mov         eax,dword ptr [ecx+0Ch]  
 
  01291063  add         eax,dword ptr [ecx+8]  
 
  01291066  add         eax,dword ptr [ecx+4]  
 
  01291069  add         eax,dword ptr [ecx]  
 
      36:     }
 
  0129106B  ret

We can see that all offsets from ecx used in both functions correspond to the memory layouts we have in the build output for the type that the function belongs to.

Since _iA and _iB are at the same offset within both CTestBase and CTestDerived (i.e. 0 and 4 bytes respectively), CTestBase::SumBase can safely be called on instances of CTestDerived.

We already know that this is possible from our high level understanding of C++, but now we know the implementational detail that makes it possible.

Whilst the specifics of the disassembly will probably differ from platform to platform, the principles underlying its operation should not.

 

Summary

To summarise what we’ve established so far :

1) in member functions, member data of a class is accessed via specific offsets from the this pointer

2) these offsets are constants at compile time and are baked into the assembly code for the member functions

3) this means that the memory layout of the members of a given class must always be identical or the member functions won’t work

 

If we follow this logic through, we can see that:

4) the memory layout of a class B that inherits from another class A must contain class A‘s members in the same memory layout as class A

5) the memory layout of any given class A is identical regardless of whether it is an instance of A, or it is included in the memory of some type derived from A. 

6) note: this behaviour is required by the standard, and (more significantly) by logic.

 

Finally, it follows that (because each member of a struct must have a higher address than those declared before it):

7) the extra memory required by derived class B will be concatenated onto the end of the memory layout of its base class A

 

That’s all for now – next time we’ll look at how multiple inheritance affects this picture.

I know it’s pretty short, but this just means the next one will get here more quickly 🙂

 

Epilogue – for those who wondered what I changed in the project settings

There’s quite  few changes to the default VS2010 win32 console app project properties in the projects I’ve zipped up for this post.

The changes have to do with making the optimised release build configuration leave the code structure alone (i.e. not strip out or ‘fold’ functions to save exe size, prevent functions being inlined), and prevent extraneous ‘debug checking’ code being inserted (makes function calls slower, and code less easy to follow in disassembly)

  • turning off ‘Whole Program Optimisation’ (Configuration Properties->General)
  • turning off ‘Inline Function Expansion’ (Configuration Properties->C/C++ ->Optimisation)
  • turning off ‘Basic Runtime Checks’ (Configuration Properties->C/C++ ->Code Generation)
  • getting rid of pre-compiled headers to streamline the number of files (Configuration Properties->C/C++ ->Precompiled Headers)
  • turning off ‘Enable COMDAT folding’ (Configuration Properties->Linker-> Optimization)

Essentially, this makes the Release configuration assembly have the same structure as the Debug one WRT function calls.

Also, I use the argc parameter to main as input to the code, and return value computed from that so that the optimiser can’t assume constant input or output values.

If you use constant inputs, or don’t output a value computed from the inputs then it’s pretty hard to convince the optimiser not to optimse the entire .exe to ‘return 0;’… 😉

 

Shout out

Thanks (again) to Bruce – king (or at the very least duke) of advice and peer review.