A brief description of the C ++ object model Memory Distribution of C ++ objects

Source: Internet
Author: User

A brief description of the C ++ object model Memory Distribution of C ++ objects
In C ++, there are two types of member variables: static and non-static. There are three member functions: static, non-static, and virtual. So how do they affect the distribution of C ++ objects in the memory? What is the memory distribution when inheritance exists?

The following is a very simple class. By gradually adding various Members to it, we will analyze the effects of the two member variables and the three member functions on the memory distribution of class objects one by one.

Note: The test results of the following code are based on G ++ 4.8.2 in 64-bit Ubuntu 14.04 systems. If other compilers are used on other systems, different results may be run.

1. Memory Distribution of objects of classes containing static member variables and member functions
The Persion class is defined as follows:

class Person{    public:        Person():mId(0), mAge(20){}        void print()        {            cout << "id: " << mId                 << ", age: " << mAge << endl;        }    private:        int mId;        int mAge;}; 

The Person class contains two non-static int-type member variables, a constructor and a non-static member function. To find out the memory distribution of objects in this class, perform the following operations on objects in this class:
int main(){    Person p1;    cout << "sizeof(p1) == " << sizeof(p1) << endl;    int *p = (int*)&p1;    cout << "p.id == " << *p << ", address: "  << p << endl;    ++p;    cout << "p.age == " << *p << ", address: " << p << endl;    cout << endl;        Person p2;    cout << "sizeof(p2) == " << sizeof(p1) << endl;    p = (int*)&p2;    cout << "p.id == " << *p << ", address: " << p << endl;    ++p;    cout << "p.age == " << *p << ", address: " << p << endl;    return 0;} 

The running result is as follows:


We can see that the class Object occupies 8 bytes of memory. Using a common int * pointer, We can traverse the values of non-static member variables in the output object, the addresses of the same non-static member variables in the two objects are different.

Based on this, we can conclude that in C ++, non-static member variables are placed in each class object, and non-static member functions are placed outside the class object, the storage sequence of non-static member variables in the memory is the same as the declared sequence in the class. Shows the Memory Distribution of person objects:



2. Memory Distribution of objects of classes containing static and non-static member variables and member functions

Add a static member variable and a static member function to the Person class as follows:
class Person{     public:         Person():mId(0), mAge(20){ ++sCount; }         ~Person(){ --sCount; }         void print()         {             cout << "id: " << mId                  << ", age: " << mAge << endl;         }         static int personCount()         {             return sCount;         }     private:         static int sCount;         int mId;         int mAge;}; 

The test code remains unchanged. It is the same as the code in section 1st. The running result is the same as that in section 1st.

Based on this, we can conclude that static member variables are stored outside the class object, and static member functions are also placed outside the class object.

Shows the memory distribution:


3. Memory Distribution of objects of classes added to virtual member functions

Add a virtual function to the Person class and change the previous print function to a function, as shown below:
class Person{    public:        Person():mId(0), mAge(20){ ++sCount; }        static int personCount()        {            return sCount;        }        virtual void print()        {            cout << "id: " << mId                 << ", age: " << mAge << endl;        }        virtual void job()        {            cout << "Person" << endl;        }        virtual ~Person()        {            --sCount;            cout << "~Person" << endl;        }    protected:        static int sCount;        int mId;        int mAge;};

To view the Memory Distribution of class objects, perform the following operation code on class objects:
int main(){    Person person;    cout << sizeof(person) << endl;    int *p = (int*)&person;    for (int i = 0; i < sizeof(person) / sizeof(int); ++i, ++p)    {        cout << *p << endl;    }    return 0;} 

The running result is as follows:


It can be seen that after the virtual member function is added, the object size of the class is 16 bytes, increasing by 8. The int * pointer is used to traverse the memory of the object. The last two rows show the value of the member data.

Virtual functions in C ++ are implemented through virtual function tables (vtbl). Each class generates a pointer for each virtual function and stores it in a table. This table is a virtual function table. Each class object is inserted with a pointer (vptr) pointing to the virtual function table of the class. Vptr settings and resetting are automatically completed by constructor, destructor, and copy assignment operators of each class.

Because my system is a 64-bit System and the size of a pointer is 8 bytes, it can be launched. In my own environment, the inserted vptr of the Class Object is placed at the top of the memory occupied by the object. The memory distribution is as follows:
Note: The sequence of virtual functions is defined in the order defined by virtual functions, but it also contains other fields. I have not yet understood what it is, in the next section, the virtual function table is described in detail.


4. virtual function table (vtbl) content and function pointer storage Sequence
In section 3rd, we can see the position of the pointer to the virtual function table (vptr) in the class, and the data in the function table is a function pointer, so we can use this to traverse the virtual function table and test the content in the virtual function table.

The test code is as follows:
typedef void (*FuncPtr)();int main(){    Person person;    int **vtbl = (int**)*(int**)&person;    for (int i = 0; i < 3 && *vtbl != NULL; ++i)    {        FuncPtr func = (FuncPtr)*vtbl;        func();        ++vtbl;    }    while (*vtbl)    {        cout << "*vtbl == " << *vtbl << endl;        ++vtbl;    }    return 0;}

Code explanation:
Because the virtual function table is located at the beginning of the object, and the virtual function table stores the pointer of the function, if the virtual function table is treated as an array, A double pointer is required to point to the array. We can get the address of the Person class object in the following way and convert it into an int ** pointer:
Person person;int **p = (int**)&person;

Use the following expression to obtain the address of the virtual function table:
int **vtbl = (int**)*p;

Then, use the following statement to obtain the function address in the virtual function table and call the function.
FuncPtr func = (FuncPtr)*vtbl;func();

Finally, you can use ++ vtbl to obtain the next address in the function table and traverse the entire virtual function table.

The running result is shown in:


As you can see, traverse the virtual function table and call the function based on the function address in the virtual function table. It calls the print function first, then the job function, and finally the destructor. The Calling sequence of the function is the same as that defined by the virtual function in the Person class. The memory distribution is consistent with the Object Memory Distribution Diagram in section 3rd. From the code and running results, we can see that the virtual function table ends with a NULL sign. However, the virtual function table also contains other data, which I have not yet understood.

5. Impact of inheritance on the memory distribution of class objects
This article does not describe the impact of inheritance on the memory distribution of objects in detail, nor introduces the implementation mechanism of virtual functions. Here we mainly provide an approximate Object Memory Model Tested by myself. Due to the large amount of code, it is not pasted out one by one. Assume that all classes have non-static member variables and member functions, static member variables, member functions, and virtual functions.
1) single inheritance (only one parent class)
Class inheritance: class Derived: public Base

The memory layout of objects in the Derived class is: virtual function table pointer, non-static member variable of the Base class, and non-static member variable of the Derived class.

2) Multi-inheritance (multiple parent classes)
The inheritance relationships of classes are as follows: class Derived: public Base1, public Base2

The memory layout of objects in the Derived class is composed of base class Base1 sub-objects and base class Base2 sub-objects and non-static member variables of the Derived class. Base-class sub-objects include their virtual function table pointers and their non-static member variables.

3) repeated inheritance (multiple inherited parent classes have the same superclasses)
The class inheritance relationship is as follows:
Class Base1: public Base
Class Base2: public Base
Class Derived: public Base1, public Base2

The memory layout of objects in the Derived class is similar to that of Multi-inheritance. However, we can see that the sub-objects of the Base class Base have a copy in the memory of objects in the Derived class. In this way, when you directly use the relevant members of the Base class in Derived, it will lead to ambiguity and can be eliminated using multiple virtual inheritance.

4) Multi-virtual inheritance (using virtual inheritance, in order to ensure that the memory layout of the inherited parent class only exists)
The class inheritance relationship is as follows:
Class Base1: virtual public Base
Class Base2: virtual public Base
Class Derived: public Base1, public Base2

The memory layout of objects in the Derived class is similar to that of objects in the inherited classes, but the sub-objects of the Base class Base are not copied, the object memory only exists in the sub-object of a Base class. But its non-static member variables are placed at the end of the object.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.