Explore C++ class memory distribution

How memory is distributed in C++ classes, especially in C++ with inheritance, virtual functions, virtual inheritance, diamond inheritance, etc.

Since the display is not as intuitive as Windows under Linux, we use VS2015 for debugging.

  • The deployment environment

    We are in the properties – > C/C + + – > command line – > / d1 reportSingleClassLayoutXXX, XXX said the name of the class;

  • Single base class

    class Base{private: int a; int b; public: void test(); };Copy the code

    Memory distribution:

    class Base size(8):   +-- -   0 | a   4 | b   +-- -
    Copy the code

    Summary: We found that the memory distribution of ordinary classes is based on the order in which they are declared, and that member functions take up no memory.

  • Base class + inherited class

    class Base{ int a; int b; public: void test(); }; class Divide :public Base{public: void run(); private: int c; int d; };Copy the code

    Memory distribution:

    class Divide size(16) :   +-- -   0 | +-- - (base class Base)   0 | | a   4 | | b | +-- -   8 | c  12 | d   +-- -
    Copy the code

    Summary: According to the memory distribution, we found that the common inheritance class, memory distribution is also in the order of declaration, member functions do not occupy memory; The order of classes is base class first, then subclass.

  • Base class that contains virtual functions

    class Base{ int a; int b; public: void test(); virtual void run(); };Copy the code

    Memory distribution:

    class Base size(12) :   +-- -   0 | {vfptr}   4 | a   8 | b   +-- -  Base::$vftable@: | &Base_meta | 0   0 | &Base::run
    Copy the code

    Summary: Memory distribution with virtual functions is divided into two parts, one is memory distribution, one is virtual table; As you can see from the top, VFPTR is placed at the beginning of memory, followed by member variables; The virtual function run is preceded by the virtual function whose serial number is 0.

  • Base class with virtual functions + inherited subclasses

    class Base{ int a; int b; public: void test(); virtual void run(); }; class Divide :public Base{public: void DivideFun(); virtual void run(); private: int c; int d; };Copy the code

    Memory distribution:

    class Divide size(20) :   +-- -   0 | +-- - (base class Base)   0 | | {vfptr}   4 | | a   8 | | b | +-- -  12 | c  16 | d   +-- -  Divide::$vftable@: | &Divide_meta | 0   0 | &Divide::run
    Copy the code

    Summary: We found that the inherited class, the virtual table only one, or at the beginning of memory, memory arrangement order is consistent with the ordinary inherited class;

  • Base class with virtual function + inherited subclass (add one more virtual function)

    class Base{ int a; int b; public: void test(); virtual void run(); }; class Divide :public Base{public: void DivideFun(); virtual void run(); virtual void DivideRun(); private: int c; int d; };Copy the code

    Memory distribution:

    class Divide size(20) :   +-- -   0 | +-- - (base class Base)   0 | | {vfptr}   4 | | a   8 | | b | +-- -  12 | c  16 | d   +-- -  Divide::$vftable@: | &Divide_meta | 0   0 | &Divide::run   1 | &Divide::DivideRun
    Copy the code

    Conclusion: The virtual table inherits from the base class. In the virtual table part, there is a virtual function with number 1 in DivideRun.

  • Multiple inheritance

    class Base{ int a; int b; public: virtual void run(); }; class Divide1 :public Base{public: virtual void run(); private: int c; }; class Divide2 :public Base{public: virtual void run(); private: int d; }; class Divide :public Divide1, Divide2{public: virtual void run(); private: int d; };Copy the code

    Memory distribution:

    class Divide1 size(16) :   +-- -   0 | +-- - (base class Base)   0 | | {vfptr} 4 | | a 8 | | b| +-- - 12 | c  +-- - Divide1::$vftable@:| &Divide1_meta| 0  0 | &Divide1::run Divide1::run this adjustor: 0 class Divide2 size(16) :  +-- -   0 | +-- - (base class Base)   0 | | {vfptr}  4 | | a  8 | | b| +-- - 12 | d  +-- - Divide2::$vftable@:| &Divide2_meta| 0  0 | &Divide2::run Divide2::run this adjustor: 0 class Divide size(36) :  +-- -   0 | +-- - (base class Divide1)   0 | | +-- - (base class Base)   0 | | | {vfptr} 4 | | | a 8 | | | b| | +-- - 12 | | c| +-- -  | +-- - (base class Divide2)  | | +-- - (base class Base)  | | | {vfptr}  | | | a  | | | b| | +-- -  | | d| +-- -  | d  +-- - Divide::$vftable@Divide1@:| &Divide_meta| 0  0 | &Divide::run Divide::$vftable@Divide2@:| -16  0 | &thunk: this -= 16; goto Divide::run Divide::run this adjustor: 0
    Copy the code

    Conclusion: basically see the last one to Divide classes, memory order first Divide1, after is Divide2, in Divide1 and Divide2 each have a virtual table;

  • Virtual inheritance (diamond inheritance)

    class Base{ int a; int b; public: virtual void run(); }; class Divide1 :virtual public Base{public: virtual void run(); private: int c; }; class Divide2 :virtual public Base{public: virtual void run(); private: int d; }; class Divide :public Divide1, Divide2{public: virtual void run(); private: int d; };Copy the code

    Memory distribution:

    class Divide1 size(20) : +-- - 0 | {vbptr} 4 | c +-- - +-- - (virtual base Base) 8 | {vfptr} 12 | a 16 | b +-- - Divide1::$vbtable@: 0 | 0 1 | 8 (Divide1d(Divide1 + 0)Base) Divide1::$vftable@: | -8 0 | &Divide1::run Divide1::run this adjustor: 8 vbi: class offset o.vbptr o.vbte fVtorDisp Base 8 0 4 0 class Divide2 size(20) : +-- - 0 | {vbptr} 4 | d +-- - +-- - (virtual base Base) 8 | {vfptr} 12 | a 16 | b +-- - Divide2::$vbtable@: 0 | 0 1 | 8 (Divide2d(Divide2 + 0)Base) Divide2::$vftable@: | -8 0 | &Divide2::run Divide2::run this adjustor: 8 vbi: class offset o.vbptr o.vbte fVtorDisp Base 8 0 4 0 class Divide size(32) : +-- - 0 | +-- - (base class Divide1) 0 | | {vbptr} 4 | | c | +-- - 8 | +-- - (base class Divide2) 8 | | {vbptr} 12 | | d  | +-- - 16 | d +-- - +-- - (virtual base Base) 20 | {vfptr} 24 | a 28 | b +-- - Divide::$vbtable@Divide1@: 0 | 0 1 | 20 (Divided(Divide1 + 0)Base) Divide::$vbtable@Divide2@: 0 | 0 1 | 12 (Divided(Divide2 + 0)Base) Divide::$vftable@: | -20 0 | &Divide::runCopy the code

    Divide: Divide1 and Divide2 are two virtual tables; Divide: three virtual tables with only one base; Divide: three virtual tables with only one base The effect of virtual inheritance is to reduce the duplication of base classes at the expense of the burden of virtual table Pointers (more needed Pointers)

First release: wechat official account background Server Development