C + + Virtual base class table pointer byte alignment

Source: Internet
Author: User

The following blog reproduced from others, I was also the problem of the pit for almost two days, about a variety of virtual base classes, virtual inheritance, virtual functions and data members, such as a series of memory-alignment issues again described in detail

Let's look at the following piece of code. Here I use an empty class K, do not be confused by this thing, I use this empty class is mainly to let it produce virtual base class table pointers and not introduce virtual base class member variables, so I can less describe some of the virtual base class member emissions, and focus on the introduction of the Virtual base class table pointer above. This empty class is a bit special, but here it is the same thing as the normal class, do not tangle this. Also, the code I directly specified the alignment parameters, so as not to cause confusion.

#include "stdafx.h"  #pragma pack (8)  class k{};     Class b:virtual k{public  :         int B;         B (): B (0xbbbbbbbb) {}  };        int _tmain (int argc, _tchar* argv[])  {         B aa;         return 0;  }   

We can break the point under the IDE, with the memory viewing window easily observe the memory layout of the object BB, this people should basically guess the approximate layout, that is, at the beginning of Class B inserted a hidden member, virtual base class table pointer, and then to B's member B, Because the virtual base class does not have a member, so the others do not need to reason, this is the reason I choose the empty class, less talk ~. The layout I caught under the VS2013 was like this:

Well, it's the same as we guessed. First, the Virtual base class table pointer is placed before the member of B. See here we can come to a small conclusion, is to join the hidden member, virtual base class table pointer, is equivalent to adding a normal pointer member variable in the class, that is, Class B can be regarded as such an equivalent layout:

Class B {void *vb_ptr; int b;}

In this case, the byte alignment and other aspects are reasonable.

So let's change it and see if we can overturn the model. We add a member variable double in B. Into this:

#include "stdafx.h"  #pragma pack (8)  class k{};     Class b:virtual k{public  :     int B;     Double B2;     B (): B (0XBBBBBBBB), B2 (0) {}  };     int _tmain (int argc, _tchar* argv[])  {     B aa;     return 0;  }  

According to the above theory, the member variable B2 of our newly added double type is exactly the same as that of member B, because the byte alignment is just right. But unfortunately the actual memory layout that was caught is this:

You see, originally there was no padding between vb_ ptr and member B, but now there are 4-byte fills, and the 4-byte padding between B2 and B can barely be understood. So the previous inference must have been incorrect. According to the present layout and the previous layout seems to be able to understand that the virtual base class table pointer is not a structure, B is a structure, virtual base class table pointer itself a structure, then the equivalent of such a layout:

Class temp{void* vb_ ptr; B TEMPB;} ;

Why is the above layout, do not understand the need to read another blog: http://www.cnblogs.com/13224ACMer/p/6287201.html

The simple explanation is as follows:

Inside the Temp class

1. Vb_ptr is a pointer with a size of 4 bytes;

2. TEMPB is a struct, and TEMPB contains a variable b of type int (4 bytes);

3. And the variable b2 of the double type (8 bytes);

A valid alignment parameter for a class or struct type is the value that is the largest of the valid alignment parameters in its members, and for the temp class, the valid alignment parameter is 8, which is the byte size of the B2 variable (double type) in TEMPB.

According to the above model can satisfy the above two cases, and as if how to change the members of the B, this model can be very good equivalence of its alignment rules. This conclusion is also wrong, the general situation is actually here, but I said to make things more complicated.

#include "stdafx.h"  #pragma pack (8)  class k{};     Class A {public  :         int A;         A (): A (0XAAAAAAAA) {}  };     Class B:virtual K, a{public  :         int B;         B (): B (0xbbbbbbbb) {}  };         int _tmain (int argc, _tchar* argv[])  {         A aa;         return 0;  }   

We changed the code to be the same as above. Let B in the virtual inheritance of the time more inherited a, and is a real inheritance. The object model of this derived class B is estimated by many to be right, according to the object layout rule, first the real base class A, then the virtual base class table pointer, and then member B. Actually the memory layout is exactly the same:

Class temp{A Tempa; void* vb_ ptr;  B TEMPB;};  

But behind, we will slowly enter the nightmare. Change the code a little bit. Change the type of member variable A of Class A to the char type. 3 classes Now change to this, the specified alignment is still 8-byte aligned, as the VC defaults.

#include "stdafx.h"  #pragma pack (8)  class k{};     Class A {public  :    char A;   Int->char    A (): A (0XAAAAAAAA) {}  };     Class B:virtual K, a{public  :    int B;    B (): B (0xbbbbbbbb) {}  };     int _tmain (int argc, _tchar* argv[])  {    B bb;    return 0;  }  
The memory layout of the B object BB crawled under the IDE is this:

How about the virtual function table after the pointer is actually filled with 4 bytes, it seems that there is absolutely no need to fill the member variable b between and B 4 bytes, even if the direct emission of B after VB_PRT is satisfied with the overall alignment rules. In this case, the alignment rules of the virtual base class table pointers seem to be somewhat related to the objects that precede them.

We change the specified alignment parameter to 4-byte alignment. See if the 4 bytes of this fill will go away. Theoretically it should disappear because the number of bytes populated must be less than the specified alignment parameter.

#include "stdafx.h"  #pragma pack (4)//pack (8)->pack (4)  class k{};     Class A {public  :         char A;  Int->char         A (): A (0XAAAAAAAA) {}  };     Class B:virtualk, a{public  :         int B;         B (): B (0xbbbbbbbb) {}  };     int _tmain (int argc, _tchar* argv[])  {         B bb;         return 0;  }   

As you can see, the padding of bytes is completely unchanged, which is indeed a violation of the alignment rules, this situation should not happen ~! This is also a place of distress to me for a long time. However, there is a more troubling place.

Change the alignment back to 8-byte alignment, and then change the type of member B of B to double.

#include "stdafx.h"  #pragma pack (8)  class k{};     Class A {public  :         char A;  Int->char         A (): A (0XAAAAAAAA) {}  };     Class B:virtualk, a{public  :         double b;//int->double         B (): B (0xbbbbbbbb) {}  };     int _tmain (int argc, _tchar* argv[])  {         B bb;         return 0;  }   

After changing the type of b from int to double, the virtual base class table pointer and B's member B are actually filled with 8 bytes. It's really unbelievable. I tried a lot of guesses, many of the models that seemed to be right on the way, but ended up with a bunch of complicated examples to overthrow ~. Of course, I think of those alignment models are very twisted, in fact, even I do not believe that it would be like that ~

Later, I did not know how the inspiration came.

"Hidden member variables", such as virtual base class table pointers and virtual function table pointers, which appear when necessary in these classes, can be summed up in a sentence with their alignment rules:

The addition of hidden members cannot affect the alignment of the members that follow.

How do you understand this sentence? To not affect the alignment rules and populated bytes of subsequent members, the total byte length inserted as a hidden member must be an integer multiple of the maximum number of valid alignment parameters in each member of the struct. This allows subsequent members to be aligned and populated "ignoring" the presence of hidden members. Hidden members do indeed belong to the members of the class.

This conclusion I have tested a lot of situations, all can, I also believe that such a concise conclusion will be the right one, in fact, I should have thought, and Microsoft's compiler such arrangements are indeed very reasonable. The various conclusions I had before were immediately turned into clouds ...

Let's try sledgehammer this rule first.

such as the most bizarre of this:

#include "stdafx.h"  #pragma pack (4)//pack (8)->pack (4)  class k{};     Class A {public  :         char A;  Int->char         A (): A (0XAAAAAAAA) {}  };     Class B:virtualk, a{public  :         int B;         B (): B (0xbbbbbbbb) {}  };     int _tmain (int argc, _tchar* argv[])  {         B bb;         return 0;  }   

The size of Class A only takes one byte, this is already its complete structure, and the 3 bytes between a and the virtual base class table pointers are the padding bytes introduced because the virtual base class table pointer itself requires 4 byte alignment, after the virtual base class table pointer, because the padding 3 bytes and the 4 bytes of the vb_ptr itself add up to 7 bytes. is not yet an integer multiple of the largest of the valid alignment parameters in structure B, the maximum alignment parameter of a member in B is an int B or a 4-byte alignment of the hidden member virtual base class table pointer itself, which is actually a valid alignment parameter for Class B itself. So we have to make one more byte behind the vb_ptr so that the members behind it will be equivalent to ignoring the alignment effect of this hidden parameter. The 3-box-out CC, in fact, is the byte fill that member B requires 4-byte alignment, so it looks like it's filled with 4 bytes. In fact, it does not violate the basic rules of byte alignment.

There are several others that can be deduced as well.

The virtual function table pointer is also a good idea, except that the virtual function table pointer is simpler, because in front of the virtual function table, either there are no members, or it is certainly already 4-byte aligned, and does not appear as a virtual base class table pointer, such as a few bytes after the previous complement of the case. Like the following:

#include "stdafx.h"  #pragma pack (8)  class A {public  :         char A;         virtual void Funa () {}         A (): A (0XAAAAAAAA) {}  };        int _tmain (int argc, _tchar* argv[])  {         A aa;         return 0;  }   

Class A has a virtual function, so a hidden member, a virtual function table pointer, is placed at the beginning of the class object, because the maximum alignment parameter of Class A is the alignment parameter 4 of the hidden member itself, and the total number of bytes introduced by the addition of the hidden member is naturally its integer multiple. So there is no need to hide the member after the padding byte, and then is the member variable a tightly followed, because a itself also to align, according to its member of the largest effective alignment as their own alignment, that is, hidden member virtual function pointer, so a itself to follow 4-byte alignment, Therefore, a 3-byte padding after a is sufficient to satisfy the alignment rules.

#include "stdafx.h"  #pragma pack (8)  class C {public  :         int C;         Double C2;         virtual void FunC () {}         C (): C (0XAAAAAAAA), C2 (0) {}  };        int _tmain (int argc, _tchar* argv[])  {         C aa;         return 0;  }   

The C class is similar, but C has a double member whose valid alignment is 8 bytes, which is the largest of the members in C, so the bytes introduced by the hidden member are an integer multiple of 8. So a virtual function pointer needs to fill at least 4 bytes and then add its own 4 bytes to satisfy the requirement.

C + + Virtual base class table pointer byte alignment

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.