Explore C++ class memory distribution together

Explore C++ class memory distribution together

91ada996f12529fbbf930481d1178a8f.png

What is the memory distribution in C++ classes, especially when C++ contains inheritance, virtual functions, virtual inheritance, and diamond inheritance.

linuxSince there is no windowslower display intuitively, we use vs2015it for debugging.


  • Deployment environment

    We are in 属性->C/C++ ->命令行 -> /d1 reportSingleClassLayoutXXX, XXX represents the class name;

4e59e8da0eeeb6e91a86869309499ee1.png
  • single base class

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

    Memory distribution:

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

    Summary : We found that the memory distribution of ordinary classes is carried out according to the order of declaration, and member functions do not occupy 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;
    };

    Memory distribution:

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

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


  • base class with virtual functions

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

    Memory distribution:

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

    Summary : The memory distribution with virtual functions is divided into two parts, one is the memory distribution, and the other is the virtual table; we found from the top that it vfptris placed at the beginning of the memory, and then the member variables; runthe front of the virtual function indicates this virtual table. The sequence number of the function is 0.


  • Base class with virtual function + inherited subclass

    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;
    };

    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

    Summary : We found that the inherited class has only one virtual table, and it is still at the beginning of the memory, and the memory arrangement order is the same as that of 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;
    };

    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

    Summary : The virtual table is still inherited from the base class, and there are more virtual functions with the DivideRunserial number in the virtual table part;1


  • 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;
    };

    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

    Summary: mainly look at the last Divideclass, the memory order is Divide1 first, then Divide2, and there is a virtual table in Divide1 and Divide2;


  • 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;
    };

    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::run

    Summary: From the memory distribution, we can see that Divide1and Divide2are two virtual tables, but Divide has become three virtual tables and only one base; so: the role of virtual inheritance is to reduce the repetition of base classes, at the cost of increasing Reduces the burden of virtual table pointers (adds more required pointers)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324146953&siteId=291194637