In depth analysis of C++ Data Member memory layout

  • 2020-04-02 01:08:47
  • OfStack

If A class only defines the class name and no methods or fields, such as class A{}; Then each instance of class A occupies 1 byte of memory, and the compiler will insert A char in this instance to ensure that each instance of A has A unique address in memory, such as A, A,b; & a! = & b. If A direct or indirect inheritance inheritance (not virtual) multiple classes, if this class and its parent class like A no way no fields, then each instance of the class size is 1 byte, if there is A virtual inheritance, it won't be 1 byte, each virtual inherit A class, an instance of the class will be more than A pointer to an inflated inherit the parent class. It's also worth noting that with classes like A, the compiler doesn't necessarily produce the legendary six methods, which are only generated when needed, such as class   If A is not used anywhere then there is no need for these method compilers to be generated. If the class is instantiated, then default constructors will be generated and destructor may not.

If a class has a static data member, a nonstatic data member, a const data member, an enum, then what's its memory layout going to look like, See the following simple class Point:


class Point
{
public:
    Point():maxCount(10){}
private:
    int X;
    static int count;
    int Y;
    const int maxCount ;
    enum{
        minCount=2
    };
};

Sizeof(Point)=12, why 12 bytes, I'm sure a lot of people know which member variables are occupied, which is X,Y,maxCount,maxCount as a constant field, but in each instance of Point there may be a different value, of course it's part of the Point instance, if you define maxCount as static, it's not part of the Point instance, if you define maxCount as static, it's not part of the Point instance, right   Const int maxCount = 1; MaxCount distribution in. The data segment, without initialization in distribution. The BSS, anyway, has nothing to do with an example of Point, the count in distribution. BSS, minCount distribution in. Rdata segment, word count, maxCount, minCount after compiling connection, memory (virtual address) are distributed, in the process of loading, will put their virtual address corresponding to the actual physical address.

Data member memory layout: nonstatic Data members in the same order in class object as they are declared, static Data   Member and const member are not in class object because they only have one copy that is Shared by class object, so static data member and const data member, enumeration does not respond to the size of class object. Segment information is something I think every C/C++ programmer must know. Point, on the other hand, only needs to allocate the memory required by X, Y, and maxCount each time it is instantiated.

The data member of each class should be continuous in memory, and if data alignment occurs, there may be white space in the middle. Look at the following classes:


class AA
{ 
protected:
    int X;
    char a; 
};
class BB:public AA
{ 
protected: 
    char b;
};
class CC:public BB
{ 
protected: 
    char c;
};

Sizeof(AA)=8// align 3 bytes
Sizeof(BB)=12// align two 3 bytes
Sizeof(CC)=16// the compiler is "shameless" with 3 3-byte alignings

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201307/201307090901345.png ">

Why would the compiler shamelessly add three 3-byte alignments to class CC so that each instance of CC is 9 bytes larger? If the compiler does not add the 9 bytes of white space, then each instance of CC is 8 bytes, the first X is 4 bytes, the last a,b,c is 3 bytes, plus 1 byte of white space alignment, exactly 8 bytes, no one too simple, sometimes naive thought best is 7 bytes.

If CC 8 bytes of memory, the same AA, BB is 8 bytes of memory, so, if you put a pointer to the AA instance is assigned to a pointer to the CC instance, then it would take eight of the AA byte directly cover the 8 bytes of CC, the CC instance of b, c are assigned a value is not what we want, it is likely to lead to your application.

The data member of the parent class will have a full copy in the instance of the subclass, so that the type conversion between the classes with inheritance relationship can be done simply by modifying the pointer.

Access to Data Member. For access to a data member, the compiler adds the starting address of the object instance to the offset of the data member. Such as CC c;

C.X = 1; This is equal to &c+(&CC::X-1), minus 1 is actually to distinguish between pointer to object or pointer to data member, data member should be minus 1. The offset of each data member is known when compiling, according to the type of the member variable and memory alignment, the existence of virtual inheritance or virtual method compiler will automatically add some auxiliary pointer, such as pointer to virtual method, pointer to virtual inheritance parent class.

In terms of access efficiency of datamember, the efficiency of struct member, class member, single inheritance or multiple inheritance is the same, because their storage is actually &obj+(&class.datamember-1). In the case of virtual inheritance, it may affect the storage performance, such as through a pointer to access a pointer to a virtual inherited data member, so performance will have influence, because at the time of virtual inheritance, also cannot be determined at compile time this data member is from parents or children, can only be deduced, at run time is actually more than a step the operation of the pointer, in virtual inheritance, if it is operating virtual inherited by an object instance data member, does not have any performance issues, because there is no polymorphism, Everything is mapped out at compile time.

Virtual inheritance or virtual methods in order to achieve polymorphism, an extra step, if you do not need polymorphism, but through the object instance to call the method is not a performance problem.


Related articles: