{"id":110069,"date":"2024-07-31T07:00:00","date_gmt":"2024-07-31T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110069"},"modified":"2024-07-31T10:03:45","modified_gmt":"2024-07-31T17:03:45","slug":"20240731-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240731-00\/?p=110069","title":{"rendered":"How to compress out interior padding in a <CODE>std::pair<\/CODE> and why you don&#8217;t want to"},"content":{"rendered":"<p><a title=\"Inside STL: The pair and the compressed pair\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230801-00\/?p=108509\"> My survey of many popular STL types began with <code>std::pair<\/code><\/a>, and in the comments, Jan Ringo\u0161 noted that the layout of a <code>std::pair<\/code> could result in padding between the two elements that could be recovered from padding within one of the elements.<\/p>\n<pre>struct bulky\r\n{\r\n    uint16_t a;\r\n    void* b;\r\n};\r\n<\/pre>\n<p>If you assume 64-bit pointers and natural alignment, then the <code>bulky<\/code> structure contains 2 bytes for <code>a<\/code>, then 6 bytes of padding to reach the next aligned pointer boundary, and then 8 bytes for <code>b<\/code>.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 16-byte structure with a two-byte field 'a' at offset 0, six bytes of padding from offsets 2 to 7, then an eight-byte field 'b' at offset 8\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<td><tt>0E<\/tt><\/td>\n<td><tt>0F<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"6\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This padding is unavoidable for <code>bulky<\/code> on its own, since you need to get <code>b<\/code> aligned on a pointer boundary, and the entire structure needs to be 8-byte aligned so that you can have an array of <code>bulky<\/code> objects.<\/p>\n<p>But what if we put it inside a <code>std::<wbr \/>pair&lt;lithe, bulky&gt;<\/code>, where <code>lithe<\/code> is something like this:<\/p>\n<pre>struct lithe\r\n{\r\n    uint16_t v;\r\n};\r\n\r\nstd::pair&lt;lithe, bulky&gt; p;\r\n<\/pre>\n<p>This produces the following <code>std::<wbr \/>pair<\/code>:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 24-byte structure with a two-byte field 'v' at offset 0 (the embedded 'first'), six bytes of padding from offsets 2 to 7, then a two-byte field 'a' at offset 8, six bytes of padding from offsets 10 through 16, then an eight-byte field 'b' at offset 16. The bytes from offsets 8 to 31 are the embedded 'second'.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<td><tt>0E<\/tt><\/td>\n<td><tt>0F<\/tt><\/td>\n<td><tt>10<\/tt><\/td>\n<td><tt>11<\/tt><\/td>\n<td><tt>12<\/tt><\/td>\n<td><tt>13<\/tt><\/td>\n<td><tt>14<\/tt><\/td>\n<td><tt>15<\/tt><\/td>\n<td><tt>16<\/tt><\/td>\n<td><tt>17<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>v<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"6\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"6\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"24\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"6\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"16\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size: 90%;\" colspan=\"2\"><tt>first<\/tt><\/td>\n<td colspan=\"6\">\u00a0<\/td>\n<td colspan=\"16\"><tt>second<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In order to ensure that the <code>bulky<\/code> starts on a pointer-aligned boundary, there are 6 bytes of padding after the <code>first<\/code>&#8216;s <code>uint16_t<\/code>, bringing the total size of the pair to 24 bytes. On the other hand, if we represented the same data in a single structure:<\/p>\n<pre>struct pair_lithe_with_bulky\r\n{\r\n    uint16_t v;\r\n    uint16_t a;\r\n    void* b;\r\n};\r\n<\/pre>\n<p>then the result would be much smaller since we could coalesce the padding.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 16-byte structure with a two-byte field 'v' at offset 0 (the embedded 'first'), a two-byte field 'a' at offset 2, four bytes of padding from offsets 4 through 7, then an eight-byte field 'b' at offset 8. The bytes from offsets 2 through 15 are the embedded 'quasi-second'.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<td><tt>0E<\/tt><\/td>\n<td><tt>0F<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>v<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"4\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"14\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size: 90%;\" colspan=\"2\"><tt>first<\/tt><\/td>\n<td colspan=\"14\">quasi-<tt>second<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Could there be a way to tell C++, &#8220;Hey, I know you need to put padding in this <code>bulky<\/code> structure, but if this structure is a subobject of another structure, just lay out the members as if they were all part of one big structure&#8221;?<\/p>\n<p>I mean, you could propose anything.<\/p>\n<p>The problem with this idea is that if you try to access <code>p.second<\/code>, you don&#8217;t get a normal <code>bulky<\/code>, but rather a wacked-out version of <code>bulky<\/code> that has a <i>misaligned<\/i> pointer, and whose size is not a multiple of its alignment.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 14-byte structure called 'quasi-second' with a two-byte field 'a' at offset 0, four bytes of padding from offsets 2 through 5, then an eight-byte field 'b' at offset 6.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"4\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"14\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td colspan=\"14\">quasi-<tt>second<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This bizarro-world version of <code>bulky<\/code> cannot be put in an array since it would misalign the subsequent element. And since its layout and size aren&#8217;t the same as that of a normal <code>bulky<\/code>, its type wouldn&#8217;t be the same as that of a normal <code>bulky<\/code>. It would have to be a &#8220;misaligned by 2 <code>bulky<\/code>&#8221; (which would need to have a name like <code>[[header_offset(2)]] bulky<\/code>). Now you have to decide what <code>std::<wbr \/>pair&lt;lithe, bulky&gt;::second_type<\/code> is. Is it <code>bulky<\/code>? Or is it <code>[[header_offset(2)]] bulky<\/code>? Either choice you make is going to create confusion, because they will cause one or the other of the following to be false:<\/p>\n<pre>\/\/ given p of type std::pair&lt;T, U&gt;\r\nstd::is_same_v&lt;U, std::pair&lt;T, U&gt;::second_type&gt;&gt;\r\nstd::is_same_v&lt;U, decltype(p.second)&gt;\r\n<\/pre>\n<p>But wait, there&#8217;s still more to fret over.<\/p>\n<p>Consider this slightly fatter version of <code>lithe<\/code>:<\/p>\n<pre>struct medium\r\n{\r\n    uint32_t v;\r\n    uint16_t w;\r\n};\r\n<\/pre>\n<p>The normal layout of the <code>std::<wbr \/>pair<\/code> would be this:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 24-byte structure with a four-byte field 'v' at offset 0, a two-byte field 'w' at offset 4, and two bytes of padding from offsets 6 to 7. The first eight bytes are the 'first' substructure. Next, a 2-byte field 'a' at offset 8, six bytes of padding from offsets 10 to 15, then an eight-byte field 'b' at offset 16. The last 16 bytes are the 'second' substructure.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<td><tt>0E<\/tt><\/td>\n<td><tt>0F<\/tt><\/td>\n<td><tt>10<\/tt><\/td>\n<td><tt>11<\/tt><\/td>\n<td><tt>12<\/tt><\/td>\n<td><tt>13<\/tt><\/td>\n<td><tt>14<\/tt><\/td>\n<td><tt>15<\/tt><\/td>\n<td><tt>16<\/tt><\/td>\n<td><tt>17<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"4\"><tt>v<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>w<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"6\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"24\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"8\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"16\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td colspan=\"8\"><tt>first<\/tt><\/td>\n<td colspan=\"16\"><tt>second<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If you try to squeeze out the padding, you end up with this quite compact structure:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 16-byte structure with a four-byte field 'v' at offset 0 and a two-byte field 'w' at offset 4. The first 6 bytes are the 'first' substructure. Next, a two-byte field 'a' at offset 6 and an eight-byte field 'b' at offset 8. The last 10 bytes are the 'second' substructure.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<td><tt>0E<\/tt><\/td>\n<td><tt>0F<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"4\"><tt>v<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>w<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"24\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"6\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"10\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td colspan=\"6\"><tt>first<\/tt><\/td>\n<td colspan=\"10\"><tt>second<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This is even more confusing because the embedded <code>medium<\/code> structure is also not a normal <code>medium<\/code> structure: It lacks the trail padding and has a size that is not a multiple of its alignment. The compiler cannot optimize<\/p>\n<pre>extern medium special;\r\np.first = special; \/\/ make the first part special\r\n<\/pre>\n<p>to a <code>memcpy(&amp;p.first, &amp;special, sizeof(medium))<\/code> because that would accidentally overwrite the <code>a<\/code> hiding inside the trail padding. It would have to be <code>memcpy(&amp;p.first, &amp;special, sizeof(medium) - trail_padding_size)<\/code> to avoid overwriting data hiding in the trail padding.<\/p>\n<p>You might think to solve the need for a <code>header_offset<\/code> attribute for alternate layouts by putting the <code>lithe<\/code> <i>inside<\/i> the padding of the <code>bulky<\/code>, assuming it fits.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 16-byte structure with a two-byte field 'a' at offset 0, a two-byte field 'v' at offset 2, four bytes of padding from offsets 4 to 7, and an eight-byte field 'b' at offset 8. The 'a' and 'b' portions are discontiguous and comprise the 'second' substructure. The 'v' field forms a 'first' substructure which fits between the two pieces of the 'second'.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td colspan=\"2\">\u00a0<\/td>\n<td style=\"font-size: 90%;\" colspan=\"2\"><tt>first<\/tt><\/td>\n<td colspan=\"12\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; border-right: none;\"><tt>02<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; border-left: none;\"><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<td><tt>0E<\/tt><\/td>\n<td><tt>0F<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>v<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"4\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"24\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"4\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"16\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size: 90%;\" colspan=\"2\"><tt>sec<\/tt>\u2026<\/td>\n<td colspan=\"6\">\u00a0<\/td>\n<td style=\"font-size: 90%;\" colspan=\"16\">\u2026<tt>ond<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Great! Now, all the structures are normal-sized and normally-aligned.<\/p>\n<p>Now you have a problem with this:<\/p>\n<pre>p.second = bulky{}; \/\/ clear out the second part\r\n<\/pre>\n<p>In order for this to work, the compiler cannot optimize the assignment to a <code>memcpy<\/code> because that would accidentally overwrite the <code>first<\/code> embedded in the internal padding.<\/p>\n<p>If you are really keen on squeezing out the padding, you can do it by setting custom packing for the <code>bulky<\/code> structure.<\/p>\n<pre>#include &lt;pshpack4.h&gt;\r\nstruct bulky\r\n{\r\n    uint16_t a;\r\n    void* b;\r\n};\r\n#include &lt;poppack.h&gt;\r\n<\/pre>\n<p>Overriding normal packing to 4-byte alignment means that you get this layout for bulky, which matches the &#8220;quasi-<code>second<\/code>&#8221; we discovered earlier.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 12-byte structure with a two-byte field 'a' at offset 0, two bytes of padding from offsets 2 through 3, and an eight-byte field 'b' at offset 4.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Hooray! This <a title=\"15 Rules for Great Food and Wine Pairing\" href=\"https:\/\/www.foodandwine.com\/food-and-wine-pairing-guide-6409590\"> pairs nicely<\/a> with <code>lithe<\/code>:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 16-byte structure with a two-byte field 'v' at offset 0 (constituting the 'first' substructure), two bytes of padding from offsets 2 through 3, a two-byte field 'a' at offset 4, two bytes of padding from offsets 6 through 7, and an eight-byte field 'b' at offset 8. The last 12 bytes (from 'a' through 'b') are the 'second' substructure.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<td><tt>0E<\/tt><\/td>\n<td><tt>0F<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>v<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>b<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"12\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size: 90%;\" colspan=\"2\"><tt>first<\/tt><\/td>\n<td style=\"font-size: 90%;\" colspan=\"2\">\u00a0<\/td>\n<td colspan=\"12\">quasi-<tt>second<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The downside of this is that systems that are alignment sensitive will have to load the <code>b<\/code> as an unaligned value, which <a title=\"Anybody who writes #pragma pack(1) may as well just wear a sign on their forehead that says &quot;I hate RISC&quot;\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200103-00\/?p=103290\"> tends to be rather expensive<\/a>. It&#8217;s not quite as bad as byte alignment, since we can often load it in just two steps instead of eight, but it&#8217;s still worse than a straight load.<\/p>\n<p>In general, this sort of tight memory optimization does save you memory, but it costs you in code flexibility (a vector of <code>bulky<\/code> objects is not going to be fun), and it can cost you in runtime costs (on alignment-sensitive platforms).<\/p>\n<p><b>Bonus chatter<\/b>: The introduction of <code>[[no_unique_address]]<\/code> in C++20 makes things more complicated. Base classes and members with the <code>[[no_unique_address]]<\/code> attribute are permitted to overlap. A common use for this is to extend the so-called empty base optimization to empty members, thereby avoiding the need for the complex dance employed by <a title=\"Inside STL: The pair and the compressed pair\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230801-00\/?p=108509\"> compressed pairs<\/a>.<\/p>\n<p>But another use for <code>[[no_unique_address]]<\/code> is to allow overlap between non-empty objects, specifically, to allow one type to hide inside the padding of another. In practice, compilers that take advantage of it\u00b2 limit themselves to reusing tail padding, so that they can still use <code>memcpy<\/code> to assign two objects (just with a smaller object size).<\/p>\n<p>In other words, it is legal for a compiler to do this:<\/p>\n<pre>struct part1\r\n{\r\n    void* ptr;\r\n    int16_t a;\r\n};\r\n\r\nstruct part2\r\n{\r\n    int32_t b;\r\n};\r\n\r\nstruct combined\r\n{\r\n    [[no_unique_address]] part1 p1;\r\n    [[no_unique_address]] part2 p2;\r\n};\r\n<\/pre>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A 16-byte structure with an eight-byte field 'ptr' at offset 0, a two-byte field 'a' at offset 8, two bytes of padding from offsets 10 through 11, and a four-byte field 'b' at offset 12. The entire structure is labeled 'p1', and the 'b' field is labeled 'p2'. The 'p1' and 'p2' overlap at 'b'.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td><tt>00<\/tt><\/td>\n<td><tt>01<\/tt><\/td>\n<td><tt>02<\/tt><\/td>\n<td><tt>03<\/tt><\/td>\n<td><tt>04<\/tt><\/td>\n<td><tt>05<\/tt><\/td>\n<td><tt>06<\/tt><\/td>\n<td><tt>07<\/tt><\/td>\n<td><tt>08<\/tt><\/td>\n<td><tt>09<\/tt><\/td>\n<td><tt>0A<\/tt><\/td>\n<td><tt>0B<\/tt><\/td>\n<td><tt>0C<\/tt><\/td>\n<td><tt>0D<\/tt><\/td>\n<td><tt>0E<\/tt><\/td>\n<td><tt>0F<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"8\"><tt>ptr<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"2\"><tt>a<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor; opacity: 15%; background-color: currentcolor;\" colspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor;\" colspan=\"4\"><tt>b<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"height: 1ex; font-size: 10%;\" colspan=\"12\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"4\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"font-size: 90%;\" colspan=\"12\">\u00a0<\/td>\n<td colspan=\"4\"><tt>p2<\/tt><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-top: none; height: 1ex; font-size: 10%;\" colspan=\"16\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td colspan=\"16\"><tt>p1<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>To avoid damaging any data hiding in the tail padding, copying a <code>part1<\/code> copies only 10 bytes instead of 16. This is not too heavy a burden on the compiler, since avoiding tail padding is easier than avoiding internal padding.<\/p>\n<p>\u00b2 The Microsoft Visual C++ compiler <a title=\"MSVC C++20 and the \/std:c++20 Switch: C++20 no_unique_address\" href=\"https:\/\/devblogs.microsoft.com\/cppblog\/msvc-cpp20-and-the-std-cpp20-switch\/#c20-no_unique_address\"> does not take advantage of <code>[[no_unique_address]]<\/code> for ABI compatibility reasons<\/a>. You have to say <code>[[msvc::no_unique_address]]<\/code> with the understanding that you are accepting the ABI break and promise not to mix code compiled in C++17 mode with code compiled in C++20 mode.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Context-sensitive layout means you get a different structure each time you use it.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-110069","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Context-sensitive layout means you get a different structure each time you use it.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110069","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=110069"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110069\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=110069"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110069"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110069"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}