My question is why doesnt the Visual Studio 2012 compiler automatically reorder struct members for best memory utilization? The compiler seems to store the members in exactly the order they are declared in the struct definition, with some empty padding as required for member alignment. It seems like reordering would be a more desirable way to align the members than padding, whenever possible. Is there a reason it must be stored in memory in declaration order?
Pertinent details follow;
I have a struct which represents a single element in what will be a large array. The element has a number of members, some 32 bit, some 64 bit. I have default struct member alignment tuned on for best performance.
I was exploring memory in debug mode and found that a signficant percentage of the memory was being wasted. I tracked the problem to how the stuct members were aligned in memory. I know that 32 bit members must be aligned on DWORD boundaries for best performance and it would appear that evidently 64 bit members must be aligned on QWORD boundaries (I would have thought DWORD boundaries would have been adequate)
I was able to fix the problem by changing the order in which I listed the members in the struct definition. I made sure to put 2 32 bit members consequtively whenever possible so that no padding is required to start the next 64 bit member on a QWORD boundary.
Data that is in a standard layout structure or class must make certain layout guarantees. Among other things if there is another standard layout structure or class that is the prefix of the first, you must be able to reinterpret one structure as the other, and the common prefix has to agree.
This basically forces the memory order of standard layout structures to be in the order you declare them.
This is similar to what C requires in terms of structure layout, as described here.
Now, in C++, there is some freedom is given for non-standard layout structures.
[expr.rel]/3 subpoint 3:
The order of elements must be maintained within public/private/protected access control domains. Space between elements can be added in nearly arbitrary ways.
This means you can know that
&this->x
is greater than or less than&this->y
, which some programmers may use.Under the as-if rule, if nobody ever takes an address of such data, the compiler could reorder them. This is hard to prove in the usual compilation models.
The spacing between elements in MSVC matches the spacing in plain old data structures, barring inheritance with virtual playing the game, in my experience. Layout compatibility (beyond the standard) is important to a stable ABI, and code compiled with one version of the compiler is preferred to work in another. Breaking that has a cost.
C++ programmers can reorder data structures as they need, and visual studio provides
#pragma
s to change the structure packing rules, so if you really need that last bit of performance you can get it.You can even write a
tuple
-like data structure that guarantees optimal packing if you need it. (I wouldn't rely onstd::tuple
, as it has no packing guarantees)