<?xml version="1.0" encoding="UTF-8" standalone="yes"?><oembed><version><![CDATA[1.0]]></version><provider_name><![CDATA[Experimental chill]]></provider_name><provider_url><![CDATA[http://danlark.org]]></provider_url><author_name><![CDATA[Danila Kutenin]]></author_name><author_url><![CDATA[https://danlark.org/author/kutdanila/]]></author_url><title><![CDATA[Why is std::pair&nbsp;broken?]]></title><type><![CDATA[link]]></type><html><![CDATA[
<p>Today we are going to talk about C++ basic <code>std::pair</code> class in a way how and why it is broken.</p>



<h2>Story</h2>



<p><code>std::pair</code> first appeared in C++98 as a pretty basic class with a very simple semantics &#8212; you have two types <code>T1</code> and <code>T2</code>, you can write <code>std::pair&lt;T1, T2&gt;</code> and access <code>.first</code> and <code>.second</code> members with all intuitive copy, assignment, comparison operators, etc. This is used in all map containers as value type to store and can be expanded into <a href="https://en.cppreference.com/w/cpp/language/structured_binding">structured bindings</a>, for example, with the following code:</p>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102347793" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-pair_easy-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-pair_easy-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-pair_easy-h-LC1" class="blob-code blob-code-inner js-file-line">std::unordered_map&lt;std::string, <span class="pl-k">int</span>&gt; m;</td>
      </tr>
      <tr>
        <td id="file-pair_easy-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-pair_easy-h-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">//</span> &#8230;</span></td>
      </tr>
      <tr>
        <td id="file-pair_easy-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-pair_easy-h-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">for</span> (<span class="pl-k">const</span> <span class="pl-k">auto</span>&amp; [key, value] : m) {</td>
      </tr>
      <tr>
        <td id="file-pair_easy-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-pair_easy-h-LC4" class="blob-code blob-code-inner js-file-line">  <span class="pl-c"><span class="pl-c">//</span> &#8230;</span></td>
      </tr>
      <tr>
        <td id="file-pair_easy-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-pair_easy-h-LC5" class="blob-code blob-code-inner js-file-line">}</td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/545f78a0e3379867a9711f59dfa9e9e0/raw/693af57ea3cca04abc1f9605199363d6e3f5dba2/pair_easy.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/545f78a0e3379867a9711f59dfa9e9e0#file-pair_easy-h">pair_easy.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div></figure>



<p>Pretty convenient, almost all C++ programmers know about this class and use it appropriately but several style guides including Google Style Guide <a href="https://google.github.io/styleguide/cppguide.html#Structs_vs._Tuples">suggest</a> using user defined structs where appropriate. It has several reasons but the first one is readability &#8212; I personally want to kill people who write more than one level of <code>std::pair</code>, for example, <code>std::pair&lt;int, std::pair&lt;int, std::pair&lt;int, int&gt;&gt;&gt;</code> and then access it with <code>el.second.second.second</code>. And as the structure of the objects in a maintainable code tends to grow, it is better to use structs rather than pairs and tuples. Other reasons are more interesting.</p>



<h2>Performance</h2>



<h3>Default construction</h3>



<p>This is a minor and debatable thing but <code>std::pair</code> with trivial and non default zero initialized scalars is zero initialized:</p>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102354299" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-pair_init-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-pair_init-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-pair_init-h-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">constexpr</span> std::pair&lt;<span class="pl-k">int</span>, <span class="pl-k">int</span>&gt; t;</td>
      </tr>
      <tr>
        <td id="file-pair_init-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-pair_init-h-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-en">static_assert</span>(t.first == <span class="pl-c1">0</span> &amp;&amp; t.second == <span class="pl-c1">0</span>);</td>
      </tr>
      <tr>
        <td id="file-pair_init-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-pair_init-h-LC3" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-pair_init-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-pair_init-h-LC4" class="blob-code blob-code-inner js-file-line">std::array&lt;<span class="pl-k">int</span>, <span class="pl-c1">5</span>&gt; arr;</td>
      </tr>
      <tr>
        <td id="file-pair_init-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-pair_init-h-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">//</span> assert(arr[0] == 0); // Undefined behavior</span></td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/013aec2d1db5b1b4fc17134112553933/raw/f55cc6e04fdbcb859bed1a2c3ca7e8e58ddd8ab6/pair_init.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/013aec2d1db5b1b4fc17134112553933#file-pair_init-h">pair_init.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div></figure>



<p>In contrast, <code>std::array</code> does not initialize their elements with the default construction (if the underlying type is trivial) and leaves this for the user. It is debatable because some people don&#8217;t like the uninitialized memory but in the end this is an inconsistency between the containers and is a different behavior from default struct what people tend to think about <code>std::pair</code> (yet, I still think this should look like this):</p>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102354363" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-fancy_pair-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-fancy_pair-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-fancy_pair-h-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">typename</span> T, <span class="pl-k">typename</span> U&gt;</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-fancy_pair-h-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-k">struct</span> <span class="pl-en">pair</span> {</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-fancy_pair-h-LC3" class="blob-code blob-code-inner js-file-line">    T first;</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-fancy_pair-h-LC4" class="blob-code blob-code-inner js-file-line">    U second;</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-fancy_pair-h-LC5" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L6" class="blob-num js-line-number" data-line-number="6"></td>
        <td id="file-fancy_pair-h-LC6" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">constexpr</span> std::strong_ordering <span class="pl-k">operator</span>&lt;=&gt;(<span class="pl-k">const</span> pair&amp; other) <span class="pl-k">const</span> {</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L7" class="blob-num js-line-number" data-line-number="7"></td>
        <td id="file-fancy_pair-h-LC7" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">if</span> (<span class="pl-k">auto</span> first_comp = first &lt;=&gt; other.<span class="pl-smi">first</span>; first_comp != <span class="pl-c1">0</span>) {</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L8" class="blob-num js-line-number" data-line-number="8"></td>
        <td id="file-fancy_pair-h-LC8" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">return</span> first_comp;</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L9" class="blob-num js-line-number" data-line-number="9"></td>
        <td id="file-fancy_pair-h-LC9" class="blob-code blob-code-inner js-file-line">        } <span class="pl-k">else</span> {</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L10" class="blob-num js-line-number" data-line-number="10"></td>
        <td id="file-fancy_pair-h-LC10" class="blob-code blob-code-inner js-file-line">            <span class="pl-k">return</span> second &lt;=&gt; other.<span class="pl-smi">second</span>;</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L11" class="blob-num js-line-number" data-line-number="11"></td>
        <td id="file-fancy_pair-h-LC11" class="blob-code blob-code-inner js-file-line">        }</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L12" class="blob-num js-line-number" data-line-number="12"></td>
        <td id="file-fancy_pair-h-LC12" class="blob-code blob-code-inner js-file-line">    }</td>
      </tr>
      <tr>
        <td id="file-fancy_pair-h-L13" class="blob-num js-line-number" data-line-number="13"></td>
        <td id="file-fancy_pair-h-LC13" class="blob-code blob-code-inner js-file-line">};</td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/42618dcdcd81894cc0805076a93af055/raw/bbecbe69ff8aa641bd9b88c03ea6bcacbba24aa2/fancy_pair.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/42618dcdcd81894cc0805076a93af055#file-fancy_pair-h">fancy_pair.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div></figure>



<h3>Copying</h3>



<p>I found this issue when I wanted to serialize and deserialize <code>std::pair</code>. One of the default implementations in struct/type serialization and deserialization is the following:</p>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102354555" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-de_serialize-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-de_serialize-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-de_serialize-h-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">class</span> <span class="pl-en">T</span>&gt;</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-de_serialize-h-LC2" class="blob-code blob-code-inner js-file-line">T <span class="pl-en">Deserialize</span>(<span class="pl-k">const</span> <span class="pl-k">void</span>* memory) {</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-de_serialize-h-LC3" class="blob-code blob-code-inner js-file-line">  T t;</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-de_serialize-h-LC4" class="blob-code blob-code-inner js-file-line">  <span class="pl-c1">memcpy</span>(&amp;t, memory, <span class="pl-k">sizeof</span>(T));</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-de_serialize-h-LC5" class="blob-code blob-code-inner js-file-line">  <span class="pl-k">return</span> t;</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L6" class="blob-num js-line-number" data-line-number="6"></td>
        <td id="file-de_serialize-h-LC6" class="blob-code blob-code-inner js-file-line">}</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L7" class="blob-num js-line-number" data-line-number="7"></td>
        <td id="file-de_serialize-h-LC7" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L8" class="blob-num js-line-number" data-line-number="8"></td>
        <td id="file-de_serialize-h-LC8" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">class</span> <span class="pl-en">T</span>&gt;</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L9" class="blob-num js-line-number" data-line-number="9"></td>
        <td id="file-de_serialize-h-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-k">void</span> <span class="pl-en">Serialize</span>(<span class="pl-k">const</span> T&amp; t, <span class="pl-k">void</span>* memory) {</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L10" class="blob-num js-line-number" data-line-number="10"></td>
        <td id="file-de_serialize-h-LC10" class="blob-code blob-code-inner js-file-line">  <span class="pl-c1">memcpy</span>(memory, &amp;t, <span class="pl-k">sizeof</span>(T));</td>
      </tr>
      <tr>
        <td id="file-de_serialize-h-L11" class="blob-num js-line-number" data-line-number="11"></td>
        <td id="file-de_serialize-h-LC11" class="blob-code blob-code-inner js-file-line">}</td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/fb6603b7144311f786d6d602c0eb3104/raw/45534ff7f42f38e453c5395eceb90e6b396c18eb/de_serialize.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/fb6603b7144311f786d6d602c0eb3104#file-de_serialize-h">de_serialize.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div></figure>



<p>If we go to <code>memcpy</code> documentation and see the following:</p>



<blockquote class="wp-block-quote"><p>If the objects are potentially-overlapping or not <a href="https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable">TriviallyCopyable</a>, the behavior of memcpy is not specified and may be undefined.</p><cite><a href="https://en.cppreference.com/w/cpp/string/byte/memcpy">https://en.cppreference.com/w/cpp/string/byte/memcpy</a></cite></blockquote>



<p>TriviallyCopyable are objects that satisfy the following conditions:</p>



<ul><li>Every copy constructor is trivial or deleted. <code>pair(const pair&amp;)</code>. So, it should be either <code>= default</code>, either <code>= delete</code>, either omitted/created by the <a href="https://en.cppreference.com/w/cpp/language/rule_of_three">rule of X</a> and all underlying objects are trivially copyable.</li><li>Every move constructor is trivial or deleted. Same with <code>pair(pair&amp;&amp;).</code></li><li>Every copy assignment operator is trivial or deleted. Same with <code>pair&amp; operator=(const pair&amp;)</code>.</li><li>Every move assignment operator is trivial or deleted. Same with <code>pair&amp; operator=(pair&amp;&amp;)</code>.</li><li>At least one copy constructor, move constructor, copy assignment operator, or move assignment operator is non-deleted.</li><li>Trivial non-deleted destructor. This means that virtual classes cannot be trivially copyable because we need to copy the implementation <a href="https://www.quora.com/What-are-vTable-and-VPTR-in-C++">vptr</a>.</li></ul>



<p>If we write our pair above and check if it is trivially copyable (with some trivial underlying types), it definitely is because we use the rule of zero and thus everything is generated automatically. Also, a small note &#8212; in the examples above you need to make sure that the types are trivially copyable, a perfect variant looks like (this is also <a href="https://llvm.org/doxygen/MemCpyOptimizer_8cpp_source.html">heavily used</a> by the compilers to generate the unaligned loads and work with unaligned memory):</p>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102356807" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-de_serialize_perfect-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-de_serialize_perfect-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-de_serialize_perfect-h-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">class</span> <span class="pl-en">T</span>&gt;</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-de_serialize_perfect-h-LC2" class="blob-code blob-code-inner js-file-line">T <span class="pl-en">Deserialize</span>(<span class="pl-k">const</span> <span class="pl-k">void</span>* memory) <span class="pl-k">noexcept</span> {</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-de_serialize_perfect-h-LC3" class="blob-code blob-code-inner js-file-line">  <span class="pl-c1">static_assert</span>(std::is_trivially_copyable_v&lt;T&gt;);</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-de_serialize_perfect-h-LC4" class="blob-code blob-code-inner js-file-line">  T t;</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-de_serialize_perfect-h-LC5" class="blob-code blob-code-inner js-file-line">  <span class="pl-c1">memcpy</span>(<span class="pl-c1">std::addressof</span>(t), memory, <span class="pl-k">sizeof</span>(T));</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L6" class="blob-num js-line-number" data-line-number="6"></td>
        <td id="file-de_serialize_perfect-h-LC6" class="blob-code blob-code-inner js-file-line">  <span class="pl-k">return</span> t;</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L7" class="blob-num js-line-number" data-line-number="7"></td>
        <td id="file-de_serialize_perfect-h-LC7" class="blob-code blob-code-inner js-file-line">}</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L8" class="blob-num js-line-number" data-line-number="8"></td>
        <td id="file-de_serialize_perfect-h-LC8" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L9" class="blob-num js-line-number" data-line-number="9"></td>
        <td id="file-de_serialize_perfect-h-LC9" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">//</span> std::remove_reference_t for non-deduced context to prevent such code to blow below:</span></td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L10" class="blob-num js-line-number" data-line-number="10"></td>
        <td id="file-de_serialize_perfect-h-LC10" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">//</span> char first = f(); char second = g();</span></td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L11" class="blob-num js-line-number" data-line-number="11"></td>
        <td id="file-de_serialize_perfect-h-LC11" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">//</span> Serialize(first &#8211; second, to) (int will be deduced)</span></td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L12" class="blob-num js-line-number" data-line-number="12"></td>
        <td id="file-de_serialize_perfect-h-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">class</span> <span class="pl-en">T</span>&gt;</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L13" class="blob-num js-line-number" data-line-number="13"></td>
        <td id="file-de_serialize_perfect-h-LC13" class="blob-code blob-code-inner js-file-line"><span class="pl-k">void</span> <span class="pl-en">Serialize</span>(<span class="pl-k">const</span> std::<span class="pl-c1">remove_reference_t</span>&lt;T&gt;&amp; t, <span class="pl-k">void</span>* memory) <span class="pl-k">noexcept</span> {</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L14" class="blob-num js-line-number" data-line-number="14"></td>
        <td id="file-de_serialize_perfect-h-LC14" class="blob-code blob-code-inner js-file-line">  <span class="pl-c1">static_assert</span>(std::is_trivially_copyable_v&lt;T&gt;);</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L15" class="blob-num js-line-number" data-line-number="15"></td>
        <td id="file-de_serialize_perfect-h-LC15" class="blob-code blob-code-inner js-file-line">  <span class="pl-c1">memcpy</span>(to, <span class="pl-c1">std::addressof</span>(t), <span class="pl-k">sizeof</span>(T));</td>
      </tr>
      <tr>
        <td id="file-de_serialize_perfect-h-L16" class="blob-num js-line-number" data-line-number="16"></td>
        <td id="file-de_serialize_perfect-h-LC16" class="blob-code blob-code-inner js-file-line">}</td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/c6b10b98efe768b77f6d2cc99703ada3/raw/6eb4e684eb4a64bd2e2569451bc24b4cb45e4b81/de_serialize_perfect.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/c6b10b98efe768b77f6d2cc99703ada3#file-de_serialize_perfect-h">de_serialize_perfect.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div></figure>



<p>Let&#8217;s see what <code>std::pair</code> guarantees. Good news is standard guarantees the copy and move constructors to be <a href="https://en.cppreference.com/w/cpp/utility/pair/pair">defaulted</a> (see 7 and 8).</p>



<p>Also, from C++17 we have the requirement that if the types of the pair are trivially destructible, pair is also trivially destructible. This allows having many optimizations including putting the type onto registers. For example, <code>std::variant</code> and <code>std::optional</code> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0602r4.html">had</a> a different proposal to make this possible.</p>



<p>With everything else, it is more complicated. Let&#8217;s see what is going on with the copy assignment, in libc++ it is implemented like this:</p>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102354996" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-pair_copy-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-pair_copy-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-pair_copy-h-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">struct</span> __nat {};</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-pair_copy-h-LC2" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-pair_copy-h-LC3" class="blob-code blob-code-inner js-file-line">pair&amp; operator=(typename conditional&lt;</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-pair_copy-h-LC4" class="blob-code blob-code-inner js-file-line">                        is_copy_assignable&lt;first_type&gt;::value &amp;&amp;</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-pair_copy-h-LC5" class="blob-code blob-code-inner js-file-line">                        is_copy_assignable&lt;second_type&gt;::value,</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L6" class="blob-num js-line-number" data-line-number="6"></td>
        <td id="file-pair_copy-h-LC6" class="blob-code blob-code-inner js-file-line">                    pair, __nat&gt;::type <span class="pl-k">const</span>&amp; __p)</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L7" class="blob-num js-line-number" data-line-number="7"></td>
        <td id="file-pair_copy-h-LC7" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">noexcept</span>(is_nothrow_copy_assignable&lt;first_type&gt;::value &amp;&amp;</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L8" class="blob-num js-line-number" data-line-number="8"></td>
        <td id="file-pair_copy-h-LC8" class="blob-code blob-code-inner js-file-line">             s_nothrow_copy_assignable&lt;second_type&gt;::value)</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L9" class="blob-num js-line-number" data-line-number="9"></td>
        <td id="file-pair_copy-h-LC9" class="blob-code blob-code-inner js-file-line">{</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L10" class="blob-num js-line-number" data-line-number="10"></td>
        <td id="file-pair_copy-h-LC10" class="blob-code blob-code-inner js-file-line">    first = __p.<span class="pl-smi">first</span>;</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L11" class="blob-num js-line-number" data-line-number="11"></td>
        <td id="file-pair_copy-h-LC11" class="blob-code blob-code-inner js-file-line">    second = __p.<span class="pl-smi">second</span>;</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L12" class="blob-num js-line-number" data-line-number="12"></td>
        <td id="file-pair_copy-h-LC12" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">return</span> *this;</td>
      </tr>
      <tr>
        <td id="file-pair_copy-h-L13" class="blob-num js-line-number" data-line-number="13"></td>
        <td id="file-pair_copy-h-LC13" class="blob-code blob-code-inner js-file-line">}</td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/c1b144401cea90549e195996aaf0908e/raw/3c06eb2f39086015a669725e938d081560350e49/pair_copy.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/c1b144401cea90549e195996aaf0908e#file-pair_copy-h">pair_copy.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div></figure>



<p><code>__nat</code> is used for disabling the instantiation of the copy assignment operator if it is invoked &#8212; a cool C++98 hack to delete the operator.</p>



<p>This helps the compiler to use <code>std::pair</code> with the references. By default, references cannot be implicitly copied or, if said in a more clever way, if you have them in the class, the copy assignment operator is implicitly deleted unless user defined. For example:</p>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102355694" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-pair_assignment-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-pair_assignment-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-pair_assignment-h-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">typename</span> T, <span class="pl-k">typename</span> U&gt;</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-pair_assignment-h-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-k">struct</span> <span class="pl-en">pair</span> {</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-pair_assignment-h-LC3" class="blob-code blob-code-inner js-file-line">    T first;</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-pair_assignment-h-LC4" class="blob-code blob-code-inner js-file-line">    U second;</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-pair_assignment-h-LC5" class="blob-code blob-code-inner js-file-line">};</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L6" class="blob-num js-line-number" data-line-number="6"></td>
        <td id="file-pair_assignment-h-LC6" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L7" class="blob-num js-line-number" data-line-number="7"></td>
        <td id="file-pair_assignment-h-LC7" class="blob-code blob-code-inner js-file-line"><span class="pl-k">int</span> <span class="pl-en">main</span>() {</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L8" class="blob-num js-line-number" data-line-number="8"></td>
        <td id="file-pair_assignment-h-LC8" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">int</span> x = <span class="pl-c1">10</span>;</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L9" class="blob-num js-line-number" data-line-number="9"></td>
        <td id="file-pair_assignment-h-LC9" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">int</span> y = <span class="pl-c1">20</span>;</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L10" class="blob-num js-line-number" data-line-number="10"></td>
        <td id="file-pair_assignment-h-LC10" class="blob-code blob-code-inner js-file-line">    pair&lt;<span class="pl-k">int</span>&amp;, <span class="pl-k">int</span>&gt; p{x, x};</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L11" class="blob-num js-line-number" data-line-number="11"></td>
        <td id="file-pair_assignment-h-LC11" class="blob-code blob-code-inner js-file-line">    pair&lt;<span class="pl-k">int</span>&amp;, <span class="pl-k">int</span>&gt; p1{y, y};</td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L12" class="blob-num js-line-number" data-line-number="12"></td>
        <td id="file-pair_assignment-h-LC12" class="blob-code blob-code-inner js-file-line">    p1 = p; <span class="pl-c"><span class="pl-c">//</span> ill-formed, with std::pair, well-formed</span></td>
      </tr>
      <tr>
        <td id="file-pair_assignment-h-L13" class="blob-num js-line-number" data-line-number="13"></td>
        <td id="file-pair_assignment-h-LC13" class="blob-code blob-code-inner js-file-line">}</td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/2a1b2304a5d863b89c41cd1f53d4b5bc/raw/6e9febf66568253926f02deabe7751aa75fe7659/pair_assignment.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/2a1b2304a5d863b89c41cd1f53d4b5bc#file-pair_assignment-h">pair_assignment.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div></figure>



<p>In C++ copying the reference changes the underlying object and thus the referenced is binded to the class. <a href="https://softwareengineering.stackexchange.com/questions/380609/from-a-language-design-perspective-is-the-reference-type-in-c-mis-designed">Here</a> is a good explanation why it was designed this way. So, the assignment operator is deleted because copying reference has slightly different semantics but in C++98 people (maybe) thought it was convenient. So, we cannot easily write <code>= default</code> to provide a default assignment operator (despite the fact this is an ABI (application binary interface) break).</p>



<p>All these facts lead to suboptimal performance, for example, in copying the vector of pairs. With the standard pair we have a simple loop, with trivially copyable type, we have fast <code>memmove</code>, the difference might be up to the register size, <code>memmove</code> is highly optimized.</p>



<figure class="wp-block-image size-large"><img data-attachment-id="268" data-permalink="https://danlark.org/2020-04-13-175618_1560x733_scrot/" data-orig-file="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png" data-orig-size="1560,733" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="2020-04-13-175618_1560x733_scrot" data-image-description="" data-image-caption="" data-medium-file="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png?w=300" data-large-file="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png?w=1024" src="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png?w=1024" alt="" class="wp-image-268" srcset="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png?w=1024 1024w, https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png?w=150 150w, https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png?w=300 300w, https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png?w=768 768w, https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png 1560w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption><a href="https://gcc.godbolt.org/z/wtLLBU">https://gcc.godbolt.org/z/wtLLBU</a></figcaption></figure>



<h4>Some attempts to fix this</h4>



<p>First of all, all fixes will require an ABI break but as C++ standard will be (I hope) more or less ok with ABI breaks (or <a href="https://cor3ntin.github.io/posts/abi/">not</a> :smile:), this can be done in a way.</p>



<p>Conceptually, we need to make a conditional default copy assignment operator with some restrictions:</p>



<ul><li>We cannot write <code>= default</code> in the main class because it disallows the assignment of the references.</li><li>We cannot add the (possibly defaulted) template arguments to the pair because it will break the forward declarations.</li><li>We cannot use SFINAE on the return types of the defaulted copy assignment operators.<ul><li><code>std::enable_if_t&lt;std::is_reference&lt;T1&gt;::value || std::is_reference&lt;T2&gt;::value&gt; operator=(const pair&amp;) = default;</code> is disallowed by the standard.</li></ul></li><li>We can move the <code>.first</code> and <code>.second</code> fields to the base classes and have partial specialisations like:</li></ul>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102356494" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-fix_pair_base_class-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-fix_pair_base_class-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-fix_pair_base_class-h-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">class</span> <span class="pl-en">T1</span>, <span class="pl-k">class</span> <span class="pl-en">T2</span>, <span class="pl-k">bool</span> is_reference&gt;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-fix_pair_base_class-h-LC2" class="blob-code blob-code-inner js-file-line"><span class="pl-k">struct</span> <span class="pl-en">MyPairBase</span>;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-fix_pair_base_class-h-LC3" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-fix_pair_base_class-h-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">//</span> Dispatch the reference specialisation and use it as a storage.</span></td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-fix_pair_base_class-h-LC5" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">class</span> <span class="pl-en">T1</span>, <span class="pl-k">class</span> <span class="pl-en">T2</span>&gt;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L6" class="blob-num js-line-number" data-line-number="6"></td>
        <td id="file-fix_pair_base_class-h-LC6" class="blob-code blob-code-inner js-file-line"><span class="pl-k">struct</span> <span class="pl-en">MyPairBase</span>&lt;T1, T2, <span class="pl-c1">false</span>&gt; {</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L7" class="blob-num js-line-number" data-line-number="7"></td>
        <td id="file-fix_pair_base_class-h-LC7" class="blob-code blob-code-inner js-file-line">    T1 a;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L8" class="blob-num js-line-number" data-line-number="8"></td>
        <td id="file-fix_pair_base_class-h-LC8" class="blob-code blob-code-inner js-file-line">    T2 b;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L9" class="blob-num js-line-number" data-line-number="9"></td>
        <td id="file-fix_pair_base_class-h-LC9" class="blob-code blob-code-inner js-file-line">    MyPairBase&amp; <span class="pl-k">operator</span>=(<span class="pl-k">const</span> MyPairBase&amp; other) = <span class="pl-k">default</span>;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L10" class="blob-num js-line-number" data-line-number="10"></td>
        <td id="file-fix_pair_base_class-h-LC10" class="blob-code blob-code-inner js-file-line">};</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L11" class="blob-num js-line-number" data-line-number="11"></td>
        <td id="file-fix_pair_base_class-h-LC11" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L12" class="blob-num js-line-number" data-line-number="12"></td>
        <td id="file-fix_pair_base_class-h-LC12" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">class</span> <span class="pl-en">T1</span>, <span class="pl-k">class</span> <span class="pl-en">T2</span>&gt;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L13" class="blob-num js-line-number" data-line-number="13"></td>
        <td id="file-fix_pair_base_class-h-LC13" class="blob-code blob-code-inner js-file-line"><span class="pl-k">struct</span> <span class="pl-en">MyPairBase</span>&lt;T1, T2, <span class="pl-c1">true</span>&gt; {</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L14" class="blob-num js-line-number" data-line-number="14"></td>
        <td id="file-fix_pair_base_class-h-LC14" class="blob-code blob-code-inner js-file-line">    T1 a;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L15" class="blob-num js-line-number" data-line-number="15"></td>
        <td id="file-fix_pair_base_class-h-LC15" class="blob-code blob-code-inner js-file-line">    T2 b;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L16" class="blob-num js-line-number" data-line-number="16"></td>
        <td id="file-fix_pair_base_class-h-LC16" class="blob-code blob-code-inner js-file-line">    MyPairBase&amp; <span class="pl-k">operator</span>=(<span class="pl-k">const</span> MyPairBase&amp; other) {</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L17" class="blob-num js-line-number" data-line-number="17"></td>
        <td id="file-fix_pair_base_class-h-LC17" class="blob-code blob-code-inner js-file-line">        a = other.<span class="pl-smi">a</span>;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L18" class="blob-num js-line-number" data-line-number="18"></td>
        <td id="file-fix_pair_base_class-h-LC18" class="blob-code blob-code-inner js-file-line">        b = other.<span class="pl-smi">b</span>;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L19" class="blob-num js-line-number" data-line-number="19"></td>
        <td id="file-fix_pair_base_class-h-LC19" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> *<span class="pl-c1">this</span>;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L20" class="blob-num js-line-number" data-line-number="20"></td>
        <td id="file-fix_pair_base_class-h-LC20" class="blob-code blob-code-inner js-file-line">    }</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L21" class="blob-num js-line-number" data-line-number="21"></td>
        <td id="file-fix_pair_base_class-h-LC21" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"><span class="pl-c">//</span> Possibly we will need to copy many things there.</span></td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L22" class="blob-num js-line-number" data-line-number="22"></td>
        <td id="file-fix_pair_base_class-h-LC22" class="blob-code blob-code-inner js-file-line">};</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L23" class="blob-num js-line-number" data-line-number="23"></td>
        <td id="file-fix_pair_base_class-h-LC23" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L24" class="blob-num js-line-number" data-line-number="24"></td>
        <td id="file-fix_pair_base_class-h-LC24" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template </span>&lt;<span class="pl-k">class</span> <span class="pl-en">T1</span>, <span class="pl-k">class</span> <span class="pl-en">T2</span>&gt;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L25" class="blob-num js-line-number" data-line-number="25"></td>
        <td id="file-fix_pair_base_class-h-LC25" class="blob-code blob-code-inner js-file-line"><span class="pl-k">struct</span> <span class="pl-en">MyPair</span> : <span class="pl-k">public</span> <span class="pl-en">MyPairBase</span>&lt;T1, T2, std::is_reference&lt;T1&gt;::value ||</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L26" class="blob-num js-line-number" data-line-number="26"></td>
        <td id="file-fix_pair_base_class-h-LC26" class="blob-code blob-code-inner js-file-line">                                          std::is_reference&lt;T2&gt;::value&gt; {</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L27" class="blob-num js-line-number" data-line-number="27"></td>
        <td id="file-fix_pair_base_class-h-LC27" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">using</span> Base = MyPairBase&lt;T1, T2, std::is_reference&lt;T1&gt;::value ||</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L28" class="blob-num js-line-number" data-line-number="28"></td>
        <td id="file-fix_pair_base_class-h-LC28" class="blob-code blob-code-inner js-file-line">                                    std::is_reference&lt;T2&gt;::value&gt;;</td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L29" class="blob-num js-line-number" data-line-number="29"></td>
        <td id="file-fix_pair_base_class-h-LC29" class="blob-code blob-code-inner js-file-line">    <span class="pl-c"><span class="pl-c">//</span> &#8230; all the implementation</span></td>
      </tr>
      <tr>
        <td id="file-fix_pair_base_class-h-L30" class="blob-num js-line-number" data-line-number="30"></td>
        <td id="file-fix_pair_base_class-h-LC30" class="blob-code blob-code-inner js-file-line">};</td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/7e961cd8adc27153e4265d39b2939717/raw/bfa75e50b3e27fc06709f8d1ea98e2d1d5bdf7b3/fix_pair_base_class.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/7e961cd8adc27153e4265d39b2939717#file-fix_pair_base_class-h">fix_pair_base_class.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div></figure>



<p>For example, <code>std::optional</code> <a href="https://github.com/llvm/llvm-project/blob/master/libcxx/include/optional#L205">does it</a> this way. The downside that we need to copy lots of code and such a simple class like optional turned out to be <a href="https://github.com/llvm/llvm-project/blob/master/libcxx/include/optional">1300+ lines of code</a>. Too much for <code>std::pair</code>, isn&#8217;t it?</p>



<p>Good solution I found is using C++20 concepts. They allow (at least they don&#8217;t disallow) the usage of the conditional default assignment operators.</p>



<figure class="wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<style>.gist table { margin-bottom: 0; }</style><div style="tab-size: 8" id="gist102356753" class="gist">
    <div class="gist-file" translate="no">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-concepts_pair-h" class="file my-2">
    
  <div itemprop="text" class="Box-body p-0 blob-wrapper data type-c  ">

      
<table class="highlight tab-size js-file-line-container" data-tab-size="8" data-paste-markdown-skip>
      <tr>
        <td id="file-concepts_pair-h-L1" class="blob-num js-line-number" data-line-number="1"></td>
        <td id="file-concepts_pair-h-LC1" class="blob-code blob-code-inner js-file-line">#<span class="pl-k">include</span> <span class="pl-s"><span class="pl-pds">&lt;</span>type_traits<span class="pl-pds">&gt;</span></span></td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L2" class="blob-num js-line-number" data-line-number="2"></td>
        <td id="file-concepts_pair-h-LC2" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L3" class="blob-num js-line-number" data-line-number="3"></td>
        <td id="file-concepts_pair-h-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">template</span>&lt;<span class="pl-k">class</span> <span class="pl-en">T1</span>, <span class="pl-k">class</span> <span class="pl-en">T2</span>&gt;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L4" class="blob-num js-line-number" data-line-number="4"></td>
        <td id="file-concepts_pair-h-LC4" class="blob-code blob-code-inner js-file-line"><span class="pl-k">struct</span> <span class="pl-en">MyPair</span> {</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L5" class="blob-num js-line-number" data-line-number="5"></td>
        <td id="file-concepts_pair-h-LC5" class="blob-code blob-code-inner js-file-line">    T1 first;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L6" class="blob-num js-line-number" data-line-number="6"></td>
        <td id="file-concepts_pair-h-LC6" class="blob-code blob-code-inner js-file-line">    T2 second;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L7" class="blob-num js-line-number" data-line-number="7"></td>
        <td id="file-concepts_pair-h-LC7" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">static</span> <span class="pl-k">constexpr</span> <span class="pl-k">bool</span> has_references = std::is_reference_v&lt;T1&gt; ||</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L8" class="blob-num js-line-number" data-line-number="8"></td>
        <td id="file-concepts_pair-h-LC8" class="blob-code blob-code-inner js-file-line">                                           std::is_reference_v&lt;T2&gt;;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L9" class="blob-num js-line-number" data-line-number="9"></td>
        <td id="file-concepts_pair-h-LC9" class="blob-code blob-code-inner js-file-line">    </td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L10" class="blob-num js-line-number" data-line-number="10"></td>
        <td id="file-concepts_pair-h-LC10" class="blob-code blob-code-inner js-file-line">    <span class="pl-en">MyPair</span>(<span class="pl-k">const</span> T1&amp; x, <span class="pl-k">const</span> T2&amp; y) : first(x), second(y) {}</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L11" class="blob-num js-line-number" data-line-number="11"></td>
        <td id="file-concepts_pair-h-LC11" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L12" class="blob-num js-line-number" data-line-number="12"></td>
        <td id="file-concepts_pair-h-LC12" class="blob-code blob-code-inner js-file-line">    MyPair&amp; <span class="pl-k">operator</span>=(<span class="pl-k">const</span> MyPair&amp;) requires(!has_references) = <span class="pl-k">default</span>;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L13" class="blob-num js-line-number" data-line-number="13"></td>
        <td id="file-concepts_pair-h-LC13" class="blob-code blob-code-inner js-file-line">    </td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L14" class="blob-num js-line-number" data-line-number="14"></td>
        <td id="file-concepts_pair-h-LC14" class="blob-code blob-code-inner js-file-line">    MyPair&amp; <span class="pl-k">operator</span>=(<span class="pl-k">const</span> MyPair&amp; other) requires(has_references) {</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L15" class="blob-num js-line-number" data-line-number="15"></td>
        <td id="file-concepts_pair-h-LC15" class="blob-code blob-code-inner js-file-line">        first = other.<span class="pl-smi">first</span>;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L16" class="blob-num js-line-number" data-line-number="16"></td>
        <td id="file-concepts_pair-h-LC16" class="blob-code blob-code-inner js-file-line">        second = other.<span class="pl-smi">second</span>;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L17" class="blob-num js-line-number" data-line-number="17"></td>
        <td id="file-concepts_pair-h-LC17" class="blob-code blob-code-inner js-file-line">        <span class="pl-k">return</span> *<span class="pl-c1">this</span>;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L18" class="blob-num js-line-number" data-line-number="18"></td>
        <td id="file-concepts_pair-h-LC18" class="blob-code blob-code-inner js-file-line">    }</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L19" class="blob-num js-line-number" data-line-number="19"></td>
        <td id="file-concepts_pair-h-LC19" class="blob-code blob-code-inner js-file-line">};</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L20" class="blob-num js-line-number" data-line-number="20"></td>
        <td id="file-concepts_pair-h-LC20" class="blob-code blob-code-inner js-file-line">
</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L21" class="blob-num js-line-number" data-line-number="21"></td>
        <td id="file-concepts_pair-h-LC21" class="blob-code blob-code-inner js-file-line"><span class="pl-k">int</span> <span class="pl-en">main</span>() {</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L22" class="blob-num js-line-number" data-line-number="22"></td>
        <td id="file-concepts_pair-h-LC22" class="blob-code blob-code-inner js-file-line">    <span class="pl-k">int</span> x = <span class="pl-c1">10</span>;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L23" class="blob-num js-line-number" data-line-number="23"></td>
        <td id="file-concepts_pair-h-LC23" class="blob-code blob-code-inner js-file-line">    MyPair&lt;<span class="pl-k">int</span>&amp;, <span class="pl-k">int</span>&gt; <span class="pl-c1">a</span>(x, <span class="pl-c1">5</span>);</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L24" class="blob-num js-line-number" data-line-number="24"></td>
        <td id="file-concepts_pair-h-LC24" class="blob-code blob-code-inner js-file-line">    MyPair&lt;<span class="pl-k">int</span>&amp;, <span class="pl-k">int</span>&gt; <span class="pl-c1">b</span>(x, <span class="pl-c1">10</span>);</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L25" class="blob-num js-line-number" data-line-number="25"></td>
        <td id="file-concepts_pair-h-LC25" class="blob-code blob-code-inner js-file-line">    b = a;</td>
      </tr>
      <tr>
        <td id="file-concepts_pair-h-L26" class="blob-num js-line-number" data-line-number="26"></td>
        <td id="file-concepts_pair-h-LC26" class="blob-code blob-code-inner js-file-line">}</td>
      </tr>
</table>


  </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/danlark1/8b412dfdda26e0577aeb74522aaa186b/raw/1b79a1595d479bb570d7ba0dfdda9263de2f9216/concepts_pair.h" style="float:right">view raw</a>
        <a href="https://gist.github.com/danlark1/8b412dfdda26e0577aeb74522aaa186b#file-concepts_pair-h">concepts_pair.h</a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>

</div><figcaption><a href="https://gcc.godbolt.org/z/XuvrC9">https://gcc.godbolt.org/z/XuvrC9</a></figcaption></figure>



<p>This fixes the problem, does not blow up the code size and at least is very intuitive to read. In the end I found several proposals trying to suggest it in a more generic way. See <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0848r0.html">one</a>, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0848r3.html">two</a> and see the <a href="https://medium.com/@barryrevzin/optional-t-in-a-possible-c-20-future-6a1f2158fb76">blog</a> where they use the feature and reduce the number of lines from 1200 to 400 for <code>std::optional</code>. Yet, I haven&#8217;t found that this was accepted but this is a very good idea of improving and simplifying things in C++.</p>



<h3>The funny</h3>



<p>I knew it already but cannot be silent about it. LLVM and GCC optimizers optimize <code>std::pair&lt;int, int&gt;</code> to use one 64 bit register. It does not do it with <code>std::tuple&lt;int, int&gt;</code>. So, if you have the choice between pair and tuple, always use pair or even user defined structs.</p>



<figure class="wp-block-image size-large"><img data-attachment-id="280" data-permalink="https://danlark.org/2020-04-13-190632_1048x543_scrot/" data-orig-file="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png" data-orig-size="1048,543" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="2020-04-13-190632_1048x543_scrot" data-image-description="" data-image-caption="" data-medium-file="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png?w=300" data-large-file="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png?w=1024" src="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png?w=1024" alt="" class="wp-image-280" srcset="https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png?w=1024 1024w, https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png?w=150 150w, https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png?w=300 300w, https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png?w=768 768w, https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-190632_1048x543_scrot.png 1048w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption><a href="https://gcc.godbolt.org/z/TCp9my">https://gcc.godbolt.org/z/TCp9my</a></figcaption></figure>



<h2>Conclusion </h2>



<p>All that was written there also applies to <code>std::tuple</code>, they have the identical behavior in many places. Yet, this is one more argument why C++ old containers and even basic things are broken and ABI stability is doing more harm than good. I will finish it with a tweet that reminds me of a <a href="https://en.wikipedia.org/wiki/CAP_theorem">CAP theorem</a>:</p>



<figure class="wp-block-embed-twitter wp-block-embed is-type-rich"><div class="wp-block-embed__wrapper">
<div class="embed-twitter"><blockquote class="twitter-tweet" data-width="500" data-dnt="true"><p lang="en" dir="ltr">Performance<br>ABI Stability<br>Ability to Change<br><br>You can pick two, choose wisely.<a href="https://twitter.com/hashtag/cppprg?src=hash&amp;ref_src=twsrc%5Etfw">#cppprg</a></p>&mdash; Bryce Adelstein Lelbach (@blelbach) <a href="https://twitter.com/blelbach/status/1228962495865507840?ref_src=twsrc%5Etfw">February 16, 2020</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
</div></figure>



<p>I really think that if at some point strong but breaking change does not happen, we will have a C++ fork that will do it.</p>
]]></html><thumbnail_url><![CDATA[https://danlarkorg.files.wordpress.com/2020/04/2020-04-13-175618_1560x733_scrot.png?fit=440%2C330]]></thumbnail_url><thumbnail_width><![CDATA[440]]></thumbnail_width><thumbnail_height><![CDATA[207]]></thumbnail_height></oembed>