MEMORY LAYOUT OF C++ OBJECT
Reading Time: 4 minutes

This is not goto material if you want strict standard or solid information. Rather it is the collection of concept I have acquired while introducing myself to C++ by googling here & there. This material is also not in order. I have just collected the answer to my quick question. And write it down here. But one thing I can assure you is that once you go through this article. You can connect many broken thought of understanding on what runs “Inside the C++ object model”. And why people call it as it runs C internally.

Note: Here I have not considered name mangling & other compiler attributes for simplicity. Also not shown how object memory layout created. I have discussed it here. Code augmentation is depends on compiler implementation, there is no standard defined as such.

Default member-functions created by the compiler inside the C++ object model

Suppose you have declared class like:

 class Thing {}; 
  • The compiler will probably synthesize this class as:
class Thing {
public:
    Thing();                        // default constructor
    Thing(const Thing&);            // copy c'tor
    Thing& operator=(const Thing&); // copy-assign
    ~Thing();                       // d'tor
    // C++11:
    Thing(Thing&&);                 // move c'tor
    Thing& operator=(Thing&&);      // move-assign
};  
  • So by default compiler will generate:
    1. default constructor
    2. copy constructor
    3. copy-assign operator
    4. destructor
    5. move constructor
    6. move-assign operator

Note: This stands true till C++ 14.

  • The compiler creates all default/implicitly-declared member-functions when it needed. A compiler cannot create default member-functions when it’s no use.

How C++ object used in function?

 X foobar()
{
    X xx;
    X *px = new X;

    // foo() is virtual function
    xx.foo();
    px->foo();

    delete px;
    return xx;
}; 
  • The probable compiler transformation would be:
 void foobar( X &_result )
{    
    X::X(&_result);                 // _result replaces local xx & constructor called    
    px = _new( sizeof( X ));        // expand X *px = new X;
    if ( px != 0 )
        px->X::X();

    foo( &_result );                // expand xx.foo(): replaced xx with _result    
    ( *px->_vtbl[ 2 ] )( px )       // expand px->foo() using virtual mechanism

    // expand delete px;
    if ( px != 0 ) {
        ( *px->_vtbl[ 1 ] )( px ); // destructor
        _delete( px );
    }
    // replace named return statement
    // no need to destroy local object xx
    return;
}; 

How class code transformed into sequential code from OOPs?

  • Let’s take the following example to understand it:
struct foo
{
    int m_var;

public:
    void print()
    {
        cout << m_var << endl;
    }
};
  • The compiler treats this as :
struct foo
{
    int m_var;
};

void print(foo *this)
{
    std::cout.operator<<(this->m_var).operator<<(std::endl);
}
  • As you can see above, objects & methods are a separate entity. An object only represents data members.
  • All the methods in class/struct contain implicit this pointer as the first argument using which all non-static data members are accessed.
  • Static data members are not part of class/struct. Because it usually resides in a data segment of memory layout. So it can be accessed directly(or using segment registers).
  • So this is the reason if you print the size of the above class. It will print 4. Because all methods are a separate entity which operates on the object by using implicit this pointer.

How & where constructor code transform/synthesize with inheritance & composition class?

class Foo 
{ 
public: 
  Foo(){cout<<"Foo"<<endl;} 
  ~Foo(){cout<<"~Foo"<<endl;} 
};

class base 
{ 
public: 
  base(){cout<<"base"<<endl;}
  ~base(){cout<<"~base"<<endl;}
};

class Bar /* : public base */
{ 
  Foo foo; 
  char *str; 
public: 
  Bar()
  {
    cout<<"Bar"<<endl;
    str = 0;
  }
  ~Bar(){cout<<"~Bar"<<endl;}
};
  • Compiler augmented Bar constructor would look like:
Bar::Bar()
{
  foo.Foo::Foo(); // augmented compiler code
  
  cout<<"Bar"<<endl; // explicit user code
  str = 0; // explicit user code
}
  • Same goes for, multiple class member objects requiring constructor initialization. The language specifies that the constructors would be invoked in the order of member declaration within the class. This is accomplished by the compiler.
  • If an object member does not define a default constructor. And a non-trivial default constructor is synthesized by a compiler for respective classes.
  • In the case of inheritance, the constructor calling sequence is started from base(top-down) to derived manner. Constructor synthesis & augmentation remain same as above. So in the above case, if you derive Bar from Base then constructor calling sequence would be Base -> Foo -> Bar.

How & where destructor code transform/synthesize with inheritance & composition class?

  • In case of the destructor, calling sequence is exactly the reverse that of a constructor. Like in the above case it would be Bar -> Foo -> Base. Synthesis & augmentation remain same as above. Access and all other things remain the same.

How & where virtual table code will be inserted?

  • The virtual table code will be inserted by the compiler before & after the user-written code in constructor & destructor. That too on demand of user implementation.
  • For the question “How virtual table code will be inserted?”, my answer is “this is purely compiler dependent”. C++ standard only mandates behaviour. Although this would not be complex. It probably would look like:
 this->_vptr[0] = type_info("class_name"); 
  • By the way, I have written a more detailed article on virtual keyword here.

Reference

Awesome
Awesome Interesting Useful Cool Boring Sucks
31