<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><generator uri="https://jekyllrb.com/" version="4.1.1">Jekyll</generator><link href="https://basit.pro/feed.xml" rel="self" type="application/atom+xml" /><link href="https://basit.pro/" rel="alternate" type="text/html" hreflang="en-US" /><updated>2026-01-13T08:23:10+00:00</updated><id>https://basit.pro/feed.xml</id><title type="html">Basit’s Developer Blog</title><subtitle>Basit&apos;s Developer Blog</subtitle><author><name>Basit Ayantunde</name><email>basitayde@gmail.com</email></author><entry><title type="html">NVIDIA CUDA-X Powers the New Sirius GPU Engine for DuckDB, Setting ClickBench Records</title><link href="https://basit.pro/sirius-leverage-cudf-jit/" rel="alternate" type="text/html" title="NVIDIA CUDA-X Powers the New Sirius GPU Engine for DuckDB, Setting ClickBench Records" /><published>2025-12-15T12:00:00+00:00</published><updated>2025-12-15T12:00:00+00:00</updated><id>https://basit.pro/sirius-leverage-cudf-jit</id><content type="html" xml:base="https://basit.pro/sirius-leverage-cudf-jit/"><![CDATA[<p>My work on cuDF’s JIT compilation was leveraged in the Sirius GPU engine for DuckDB, which achieved record-setting performance on the ClickBench benchmark. This article highlights how the JIT compilation techniques I developed enabled Sirius to deliver unprecedented query performance by generating optimized GPU code on-the-fly.</p>

<p><a href="https://developer.nvidia.com/blog/nvidia-gpu-accelerated-sirius-achieves-record-setting-clickbench-record/">Read the full article on NVIDIA Developer Blog</a></p>]]></content><author><name>Basit Ayantunde</name><email>basitayde@gmail.com</email></author><category term="jit" /><category term="gpu" /><category term="c++" /><category term="nvidia" /><summary type="html"><![CDATA[My work on cuDF’s JIT compilation was leveraged in the Sirius GPU engine for DuckDB, which achieved record-setting performance on the ClickBench benchmark. This article highlights how the JIT compilation techniques I developed enabled Sirius to deliver unprecedented query performance by generating optimized GPU code on-the-fly.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://basit.pro/sirius-leverage-cudf-jit/sirius.webp" /><media:content medium="image" url="https://basit.pro/sirius-leverage-cudf-jit/sirius.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Efficient Transforms in cuDF Using JIT Compilation</title><link href="https://basit.pro/efficient-transforms-cudf-jit/" rel="alternate" type="text/html" title="Efficient Transforms in cuDF Using JIT Compilation" /><published>2025-08-07T13:00:00+01:00</published><updated>2025-08-07T13:00:00+01:00</updated><id>https://basit.pro/efficient-transforms-cudf-jit</id><content type="html" xml:base="https://basit.pro/efficient-transforms-cudf-jit/"><![CDATA[<p>I authored this article for NVIDIA’s Developer Blog, exploring how Just-In-Time (JIT) compilation enables efficient data transformations in cuDF. The work demonstrates how JIT compilation can significantly improve performance for GPU-accelerated dataframe operations by generating optimized code at runtime, eliminating the overhead of traditional interpreter-based approaches.</p>

<p><a href="https://developer.nvidia.com/blog/efficient-transforms-in-cudf-using-jit-compilation/">Read the full article on NVIDIA Developer Blog</a></p>]]></content><author><name>Basit Ayantunde</name><email>basitayde@gmail.com</email></author><category term="jit" /><category term="gpu" /><category term="c++" /><category term="nvidia" /><summary type="html"><![CDATA[I authored this article for NVIDIA’s Developer Blog, exploring how Just-In-Time (JIT) compilation enables efficient data transformations in cuDF. The work demonstrates how JIT compilation can significantly improve performance for GPU-accelerated dataframe operations by generating optimized code at runtime, eliminating the overhead of traditional interpreter-based approaches.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://basit.pro/efficient-transforms-cudf-jit/cudf.png" /><media:content medium="image" url="https://basit.pro/efficient-transforms-cudf-jit/cudf.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Better identifying conda packages with ClearlyDefined</title><link href="https://basit.pro/better-identifying-conda-packages/" rel="alternate" type="text/html" title="Better identifying conda packages with ClearlyDefined" /><published>2024-07-23T13:00:00+01:00</published><updated>2024-07-23T13:00:00+01:00</updated><id>https://basit.pro/better-identifying-conda-packages</id><content type="html" xml:base="https://basit.pro/better-identifying-conda-packages/"><![CDATA[<p>I contributed to improving package identification in the conda ecosystem through ClearlyDefined, an Open Source Initiative project. This work focused on enhancing the accuracy and completeness of metadata for conda packages, making it easier to track licensing, provenance, and dependencies across the conda package management ecosystem.</p>

<p><a href="https://opensource.org/blog/better-identifying-conda-packages-with-clearlydefined">Read the full article on Open Source Initiative Blog</a></p>]]></content><author><name>Basit Ayantunde</name><email>basitayde@gmail.com</email></author><category term="conda" /><category term="package-management" /><summary type="html"><![CDATA[I contributed to improving package identification in the conda ecosystem through ClearlyDefined, an Open Source Initiative project. This work focused on enhancing the accuracy and completeness of metadata for conda packages, making it easier to track licensing, provenance, and dependencies across the conda package management ecosystem.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://basit.pro/better-identifying-conda-packages/conda.png" /><media:content medium="image" url="https://basit.pro/better-identifying-conda-packages/conda.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The C++ Object Lifecycle</title><link href="https://basit.pro/cpp-object-lifecycle/" rel="alternate" type="text/html" title="The C++ Object Lifecycle" /><published>2024-05-25T13:00:00+01:00</published><updated>2024-05-25T13:00:00+01:00</updated><id>https://basit.pro/cpp-object-lifecycle</id><content type="html" xml:base="https://basit.pro/cpp-object-lifecycle/"><![CDATA[<p>Most Discussions around RAII/C++ Objects don’t discuss the implicit contracts required to maintain the object’s validity. These contracts are required when implementing your custom container types, working with custom memory allocators, tag discriminated unions (i.e. <a href="https://github.com/lamarrr/ashura/blob/ec183d8cb6109c263e5b6b0f070079bf3db65230/ashura/std/result.h#L29"><code class="language-plaintext highlighter-rouge">Result&lt;T, E&gt;</code></a> and <a href="https://github.com/lamarrr/ashura/blob/ec183d8cb6109c263e5b6b0f070079bf3db65230/ashura/std/option.h#L25"><code class="language-plaintext highlighter-rouge">Option&lt;T&gt;</code></a>, <a href="https://en.cppreference.com/w/cpp/utility/variant"><code class="language-plaintext highlighter-rouge">std::variant&lt;T...&gt;</code></a>), etc.</p>

<p>These are typically termed as ‘unsafe’ operations as they do require an understanding of the Object lifetime invariants or lifecycle.
I would assume some basic familiarity with assembly as it is difficult to make sense of some of the article’s experiments without them.</p>

<p><strong>NOTE</strong>: We will not discuss exceptions nor the corner cases, unnecessary complexities, code path explosions, and limitations they introduce.</p>

<p>The lifecycle of a C++ Object is illustrated as:</p>

<pre><code class="language-txt">  allocate placement memory
             ||
             ||                     ============
             \/                     ||        ||
====&gt;  construct object  ===&gt; assign object &lt;===
||           ||                     ||
||           \/                     ||
====== destruct object  &lt;=============
             ||
             \/
 deallocate placement memory
</code></pre>

<p>A violation of this lifecycle <strong>WILL</strong> lead to undefined behavior, typically: memory leak, double-free, uninitialized memory read/write, unaligned read/writes, <code class="language-plaintext highlighter-rouge">nullptr</code> dereference, out-of-bound read/writes, etc.</p>

<p>A rule of thumb I use for testing lifecycle violations in containers is to ensure the number of constructions is equal to the number of destructions. The types we will be using for demonstrating some of these concepts are defined as follows:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">struct</span> <span class="nc">Counter</span> <span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="n">num_constructs</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">num_destructs</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="kt">void</span> <span class="n">log</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"num_constructs = %"</span> <span class="n">PRIu32</span> <span class="s">" </span><span class="se">\n</span><span class="s">num_destructs =  %"</span> <span class="n">PRIu32</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
               <span class="n">num_constructs</span><span class="p">,</span> <span class="n">num_destructs</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span> <span class="n">counter</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Obj</span> <span class="p">{</span>
    <span class="c1">// default-construction</span>
    <span class="n">Obj</span><span class="p">()</span> <span class="p">{</span> <span class="n">counter</span><span class="p">.</span><span class="n">num_constructs</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span>
    <span class="c1">// copy-construction</span>
    <span class="n">Obj</span><span class="p">(</span><span class="n">Obj</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">)</span> <span class="o">:</span> <span class="n">data</span><span class="p">{</span><span class="n">t</span><span class="p">.</span><span class="n">data</span><span class="p">}</span> <span class="p">{</span> <span class="n">counter</span><span class="p">.</span><span class="n">num_constructs</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span>
    <span class="c1">// move-construction</span>
    <span class="n">Obj</span><span class="p">(</span><span class="n">Obj</span><span class="o">&amp;&amp;</span> <span class="n">t</span><span class="p">)</span> <span class="o">:</span> <span class="n">data</span><span class="p">{</span><span class="n">t</span><span class="p">.</span><span class="n">data</span><span class="p">}</span> <span class="p">{</span> <span class="n">counter</span><span class="p">.</span><span class="n">num_constructs</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span>
    <span class="c1">// copy-assignment</span>
    <span class="n">Obj</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="n">Obj</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">data</span> <span class="o">=</span> <span class="n">t</span><span class="p">.</span><span class="n">data</span><span class="p">;</span>
        <span class="k">return</span> <span class="o">*</span><span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="c1">// move-assignment</span>
    <span class="n">Obj</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="n">Obj</span><span class="o">&amp;&amp;</span> <span class="n">t</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">data</span> <span class="o">=</span> <span class="n">t</span><span class="p">.</span><span class="n">data</span><span class="p">;</span>
        <span class="k">return</span> <span class="o">*</span><span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="c1">// destruction</span>
    <span class="o">~</span><span class="n">Obj</span><span class="p">()</span> <span class="p">{</span> <span class="n">counter</span><span class="p">.</span><span class="n">num_destructs</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span>
    <span class="kt">uint32_t</span> <span class="n">data</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">};</span>


</code></pre></div></div>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">struct</span> <span class="nc">Animal</span> <span class="p">{</span>
    <span class="k">virtual</span> <span class="kt">void</span> <span class="n">react</span><span class="p">()</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">Cat</span> <span class="o">:</span> <span class="n">Animal</span> <span class="p">{</span>
    <span class="kt">void</span> <span class="n">react</span><span class="p">()</span> <span class="k">override</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"purr...</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">Dog</span> <span class="o">:</span> <span class="n">Animal</span> <span class="p">{</span>
    <span class="kt">void</span> <span class="n">react</span><span class="p">()</span> <span class="k">override</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"woof!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>

</code></pre></div></div>

<h5 id="allocate-memory">Allocate Memory</h5>

<p>An object’s memory <strong>can</strong> be sourced from the stack (i.e. <code class="language-plaintext highlighter-rouge">alloca</code>, <code class="language-plaintext highlighter-rouge">malloca</code>) or heap (i.e. <code class="language-plaintext highlighter-rouge">sbrk</code>, <code class="language-plaintext highlighter-rouge">malloc</code>, <code class="language-plaintext highlighter-rouge">kalloc</code>) and have some base requirements for objects to be placed on them:</p>

<ul>
  <li>On successful allocation, the memory returned by allocators <strong>MUST</strong> be valid and not be already in use.
This prevents catastrophic failures like double-free (double-object destructor calls).</li>
</ul>

<p><strong>SEE</strong>: GNUC’s <a href="https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html"><code class="language-plaintext highlighter-rouge">__attribute__((malloc(...)))</code></a> and MSVC’s <a href="https://learn.microsoft.com/en-us/cpp/cpp/restrict?view=msvc-170"><code class="language-plaintext highlighter-rouge">__restrict</code></a> return attributes which enable global aliasing optimizations for the compiler’s reachability analysis.</p>

<p><strong>NOTE</strong>: <code class="language-plaintext highlighter-rouge">malloc(0)</code> and <code class="language-plaintext highlighter-rouge">realloc(ptr, 0, 0)</code> are not required to return <code class="language-plaintext highlighter-rouge">nullptr</code> and is implementation-defined behavior. An implementation <strong>MIGHT</strong> decide to return the same or different non-null (possibly sentinel) memory address for a 0-sized allocation.</p>

<ul>
  <li>General-purpose allocators <strong>SHOULD</strong> support at least alignment of <code class="language-plaintext highlighter-rouge">alignof(max_align_t)</code> where <a href="https://en.cppreference.com/w/c/types/max_align_t"><code class="language-plaintext highlighter-rouge">max_align_t</code></a> is mostly either <code class="language-plaintext highlighter-rouge">double</code> (8 bytes) or <code class="language-plaintext highlighter-rouge">long double</code> (16 bytes), as in the case of <code class="language-plaintext highlighter-rouge">malloc</code>. <code class="language-plaintext highlighter-rouge">max_align_t</code> is a maximum-aligned integral scalar type.</li>
</ul>

<p><strong>NOTE</strong>: C11 introduced <a href="https://en.cppreference.com/w/c/memory/aligned_alloc"><code class="language-plaintext highlighter-rouge">aligned_alloc</code></a> for over-aligned allocations (beyond <code class="language-plaintext highlighter-rouge">alignof(max_align_t)</code>) which is typically required for SIMD vector operations (SSE/AVX’s 128-bit, 256-bit, and 512-bit extensions) as the SIMD’s wide registers operate on over-aligned memory addresses. <code class="language-plaintext highlighter-rouge">MSVC</code>’s C runtime doesn’t support <code class="language-plaintext highlighter-rouge">aligned_alloc</code> yet but provides <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-malloc?view=msvc-170"><code class="language-plaintext highlighter-rouge">_aligned_malloc</code></a> and <a href="https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-free?view=msvc-170"><code class="language-plaintext highlighter-rouge">_aligned_free</code></a>.</p>

<h4 id="construct-object">Construct Object</h4>

<p>This is where the lifecycle of an object begins. For non-trivially constructible types this implies a placement new of the object on the placement memory and for trivially constructible types, any memory write operation on the object’s placement memory.</p>

<p>The object’s placement memory address <strong>MUST</strong> be sized to <em>at least</em> the object’s size and the object placement address within the memory <strong>MUST</strong> be aligned to a multiple of the object’s alignment. If an object is constructed at a memory location not properly sized for it, it can lead to Undefined Behavior (out-of-bound reads). Non-suitably aligned placement memory can lead to unaligned read &amp; writes (undefined behavior, which on some CPU architectures can crash your application with a <code class="language-plaintext highlighter-rouge">SIGILL</code> or just lead to degraded performance).
Reading an uninitialized/non-constructed object is Undefined Behavior and catastrophic.</p>

<p>Placement-new serves some important purposes:</p>

<ul>
  <li>initializing virtual function dispatch table for virtual (base and inherited) classes. (trivial construction i.e. <code class="language-plaintext highlighter-rouge">memset</code> or <code class="language-plaintext highlighter-rouge">memcpy</code> is not enough)</li>
  <li>initializing the class/struct, its base classes, and its members</li>
</ul>

<p>Let’s look at these in practice:</p>

<p><a href="https://godbolt.org/z/fq9KdP1eo"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="o">*</span> <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span> <span class="n">malloc</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>
<span class="p">(</span><span class="o">*</span><span class="n">x</span><span class="p">)</span><span class="o">++</span><span class="p">;</span> <span class="c1">// undefined behavior</span>
</code></pre></div></div>

<p>The code above invokes undefined behavior due to an uninitialized read of an <code class="language-plaintext highlighter-rouge">int</code> at memory x.
With optimizations enabled, the compiler can aggressively decide to ignore the increment operation.</p>

<p>To fix:</p>

<p><a href="https://godbolt.org/z/fq9KdP1eo"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="o">*</span> <span class="n">x</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="o">*</span><span class="p">)</span> <span class="n">malloc</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>
<span class="o">*</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">(</span><span class="o">*</span><span class="n">x</span><span class="p">)</span><span class="o">++</span><span class="p">;</span>
</code></pre></div></div>

<p>Because <code class="language-plaintext highlighter-rouge">int</code> is a trivially constructible type (i.e. no special construction semantics) with no invariants, it can be constructed simply by writing to the memory address, and an <code class="language-plaintext highlighter-rouge">int</code> “object” would implicitly exist at memory address <code class="language-plaintext highlighter-rouge">x</code>.
To construct an <code class="language-plaintext highlighter-rouge">int</code> or trivially constructible object at address <code class="language-plaintext highlighter-rouge">x</code> You can also use:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">placement new</code></li>
  <li><code class="language-plaintext highlighter-rouge">memcpy</code>/<code class="language-plaintext highlighter-rouge">memmove</code></li>
  <li><code class="language-plaintext highlighter-rouge">memset</code>/<code class="language-plaintext highlighter-rouge">memset_explicit</code></li>
</ul>

<p>Now, let’s take a look at a type with a more complex construction semantic (non-trivially-constructible):</p>

<p><a href="https://godbolt.org/z/Kn3bccore"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Obj</span><span class="o">*</span> <span class="n">obj</span> <span class="o">=</span> <span class="p">(</span><span class="n">Obj</span><span class="o">*</span><span class="p">)</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">Obj</span><span class="p">));</span>
<span class="n">obj</span><span class="o">-&gt;</span><span class="n">data</span><span class="o">++</span><span class="p">;</span> <span class="c1">// undefined behavior, data is random value</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"data: %"</span> <span class="n">PRIu32</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">obj</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">);</span>
<span class="n">counter</span><span class="p">.</span><span class="n">log</span><span class="p">();</span> <span class="c1">// num_constructs = 0, num_destructs = 0</span>
</code></pre></div></div>

<p>From the log above, you can see the Object is never constructed at address <code class="language-plaintext highlighter-rouge">obj</code>, so, no object of type <code class="language-plaintext highlighter-rouge">Obj</code> exists at <code class="language-plaintext highlighter-rouge">obj</code> yet and it is undefined behavior to use/destroy the object in that state.
This could lead to a number of contract violations/undefined behavior like double-free, out-of-bounds reads/writes.</p>

<p>To fix:</p>

<p><a href="https://godbolt.org/z/1M58e85Mh"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Obj</span><span class="o">*</span> <span class="n">obj</span> <span class="o">=</span> <span class="p">(</span><span class="n">Obj</span><span class="o">*</span><span class="p">)</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">Obj</span><span class="p">));</span>
<span class="k">new</span> <span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="n">Obj</span><span class="p">{};</span>  <span class="c1">// constructs object of type Obj at the address</span>
<span class="n">obj</span><span class="o">-&gt;</span><span class="n">data</span><span class="o">++</span><span class="p">;</span>  <span class="c1">// ok: data is increased from default value of 1 to 2</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"data: %"</span> <span class="n">PRIu32</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">obj</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">);</span>
<span class="n">counter</span><span class="p">.</span><span class="n">log</span><span class="p">();</span>  <span class="c1">// num_constructs = 1, num_destructs = 0</span>
</code></pre></div></div>

<p>The placement new constructs the object of type <code class="language-plaintext highlighter-rouge">Obj</code> at address <code class="language-plaintext highlighter-rouge">obj</code>, and now contains valid member <code class="language-plaintext highlighter-rouge">data</code>.</p>

<p>Placement-new also serves to initialize the virtual function table pointers for the object to be usable in virtual dispatch.
The compiler’s reachability analysis <strong>MIGHT</strong> decide an object doesn’t exist at a memory address if it is not constructed with placement new and thus invoke undefined behavior. To illustrate:</p>

<p><a href="https://godbolt.org/z/aMMGe1n8o"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Cat</span> <span class="o">*</span> <span class="n">cat</span> <span class="o">=</span> <span class="p">(</span><span class="n">Cat</span><span class="o">*</span><span class="p">)</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">Cat</span><span class="p">));</span>
<span class="n">memset</span><span class="p">(</span><span class="n">cat</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">Cat</span><span class="p">));</span>
<span class="n">cat</span><span class="o">-&gt;</span><span class="n">react</span><span class="p">();</span> <span class="c1">// static dispatches to Cat::react()</span>
<span class="n">Animal</span> <span class="o">*</span> <span class="n">animal</span> <span class="o">=</span> <span class="n">cat</span><span class="p">;</span>
<span class="n">animal</span><span class="o">-&gt;</span><span class="n">react</span><span class="p">();</span> <span class="c1">// undefined behavior</span>
</code></pre></div></div>

<p>Calling <code class="language-plaintext highlighter-rouge">cat-&gt;react()</code>, correctly calls <code class="language-plaintext highlighter-rouge">Cat::react</code> via static dispatch. However with dynamic dispatch from its Base class method <code class="language-plaintext highlighter-rouge">Animal::react</code> via the type-erased call <code class="language-plaintext highlighter-rouge">animal-&gt;react()</code>, the compiler <strong>CAN</strong> decide to simply elide/ignore it given it is undefined behavior (invocation of a null function pointer), if in debug mode or the compiler’s reachability analysis is unable to see the <code class="language-plaintext highlighter-rouge">memset</code> it could lead to a segmentation fault.</p>

<p>To examine why this happens, let’s take a look at implementing implement a virtual class with a custom dynamic dispatch/v-table:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">Animal</span><span class="p">{</span>
 <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">react</span><span class="p">)(</span><span class="kt">void</span> <span class="o">*</span><span class="p">);</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">Cat</span><span class="p">{</span>
  <span class="n">Animal</span> <span class="n">animal</span><span class="p">{</span>
    <span class="p">.</span><span class="n">react</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">react</span>
  <span class="p">};</span>
 <span class="k">static</span> <span class="kt">void</span> <span class="n">react</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">);</span>
<span class="p">};</span>

</code></pre></div></div>

<p>For virtual dispatch to occur, the function pointer <code class="language-plaintext highlighter-rouge">Animal::react</code> would need to be called, but in the former example <code class="language-plaintext highlighter-rouge">Animal::react</code> would have been initialized to <code class="language-plaintext highlighter-rouge">0</code> by the <code class="language-plaintext highlighter-rouge">memset</code> call which is undefined behavior when <code class="language-plaintext highlighter-rouge">animal-&gt;react()</code> is invoked.</p>

<p>To fix our previous example, we would need to correctly initialize the implementation-defined virtual function dispatch table via the placement-new call, i.e:</p>

<p><a href="https://godbolt.org/z/z3rds6hPc"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Cat</span> <span class="o">*</span> <span class="n">cat</span> <span class="o">=</span> <span class="p">(</span><span class="n">Cat</span><span class="o">*</span><span class="p">)</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">Cat</span><span class="p">));</span>
<span class="k">new</span> <span class="p">(</span><span class="n">cat</span><span class="p">)</span> <span class="n">Cat</span><span class="p">{};</span> <span class="c1">// initializes v-table</span>
<span class="n">cat</span><span class="o">-&gt;</span><span class="n">react</span><span class="p">();</span> <span class="c1">// static dispatches to Cat::react()</span>
<span class="n">Animal</span> <span class="o">*</span> <span class="n">animal</span> <span class="o">=</span> <span class="n">cat</span><span class="p">;</span>
<span class="n">animal</span><span class="o">-&gt;</span><span class="n">react</span><span class="p">();</span> <span class="c1">// OK</span>
</code></pre></div></div>

<p>The virtual function call <code class="language-plaintext highlighter-rouge">animal-&gt;react()</code> now correctly dispatches to <code class="language-plaintext highlighter-rouge">Cat::react</code>.</p>

<p><strong>NOTE</strong>: The C++ standard doesn’t specify how virtual dispatch/virtual function tables should be implemented, so there’s no portable way to reliably manipulate the runtime’s virtual function table.</p>

<p>Copy and Move construction implies the source address is already constructed with an object, and the destination address is a scratch memory containing uninitialized object/memory that needs to be initialized. Note that Copy and Move construction <strong>SHOULD</strong> not call the destructors of either the source or destination objects.</p>

<p>Object construction is also split into several categories, namely:</p>

<ul>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_constructible">non-trivial construction</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_copy_constructible">non-trivial copy construction</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_move_constructible">non-trivial move construction</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_constructible">trivial construction</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_copy_constructible">trivial copy construction</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_move_constructible">trivial move construction</a></li>
</ul>

<h4 id="assign-object">Assign Object</h4>

<p>Copy and Move assignment requires that an object already exists at a memory address and we would like to assign another object to it. Meaning both the source and destination addresses contain valid initialized objects.
Object Assignment is split into several categories, namely:</p>

<ul>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_copy_assignable">copy assignment (<code class="language-plaintext highlighter-rouge">T&amp; operator=(U const&amp;)</code>)</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_move_assignable">move assignment (<code class="language-plaintext highlighter-rouge">T&amp; operator=(U &amp;&amp;)</code>)</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_copy_assignable">trivial copy assignment</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_move_assignable">trivial move assignment</a></li>
</ul>

<p>Assignment being trivial means the objects can be assigned to another object without a special operation, this means it can be copied bytewise, i.e. via a <code class="language-plaintext highlighter-rouge">memcpy</code> or <code class="language-plaintext highlighter-rouge">memmove</code>.</p>

<h4 id="destruct-object">Destruct Object</h4>

<p>Destruction requires that a valid object exists at a memory location.
Destructing an object at a memory address implies that no object exists at that memory address and the memory is now left in an uninitialized state.</p>

<p>Unlike trivial constructions and assignments, trivial destruction implies a no-op.</p>

<ul>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_destructible">non-trivial destruction (<code class="language-plaintext highlighter-rouge">~T()</code>)</a></li>
  <li><a href="https://en.cppreference.com/w/cpp/types/is_destructible">trivial destruction</a></li>
</ul>

<h4 id="deallocate-memory">Deallocate Memory</h4>

<p>Deallocating memory requires that any object on the placement memory has been destroyed. The memory is returned to its allocator and <strong>SHOULD</strong> no longer be referenced or used.</p>

<h2 id="applications">Applications</h2>

<h4 id="strict-aliasing-dead-store-and-dead-load-optimizations">Strict Aliasing, Dead-store, and Dead-load Optimizations</h4>

<p>Strict aliasing is a very important contract that enables an aggressive compiler optimization called dead-store and dead-load optimizations</p>

<p>consider:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">A</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="nc">B</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">};</span>

<span class="n">A</span> <span class="o">*</span> <span class="n">a</span> <span class="o">=</span> <span class="n">get_A</span><span class="p">();</span>
<span class="n">B</span> <span class="o">*</span> <span class="n">b</span> <span class="o">=</span> <span class="n">get_B</span><span class="p">();</span>

<span class="n">a</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="n">b</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="k">return</span> <span class="n">a</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">;</span>

</code></pre></div></div>

<p>Here, we first write to <code class="language-plaintext highlighter-rouge">a</code> and then to <code class="language-plaintext highlighter-rouge">b</code>, Consider that <code class="language-plaintext highlighter-rouge">a</code> might be a <code class="language-plaintext highlighter-rouge">reinterpret_cast</code> of <code class="language-plaintext highlighter-rouge">b</code>, then we wouldn’t be able to assume the value of <code class="language-plaintext highlighter-rouge">a</code> is still 6 because there’s a possibility both are pointing to either the same or different objects.
Whilst the implications of this at scale are non-obvious, it becomes drastic when the compiler’s reachability analysis can’t prove they are distinct objects.</p>

<p>Consider the reasonable contract that type <code class="language-plaintext highlighter-rouge">A</code> can not alias (<code class="language-plaintext highlighter-rouge">reinterpret_cast</code>) type <code class="language-plaintext highlighter-rouge">B</code> then we can always perform an optimization and assume both objects are different, therefore mutations to type <code class="language-plaintext highlighter-rouge">B</code> can not be observed from type <code class="language-plaintext highlighter-rouge">A</code>.</p>

<p>However, we would still need a backdoor in case we need to copy byte-wise from <code class="language-plaintext highlighter-rouge">a</code> to <code class="language-plaintext highlighter-rouge">b</code>, the exception to the contract being that <code class="language-plaintext highlighter-rouge">char</code>, <code class="language-plaintext highlighter-rouge">unsigned char</code>, and <code class="language-plaintext highlighter-rouge">signed char</code> can alias any object, otherwise encapsulated by <a href="https://en.cppreference.com/w/cpp/numeric/bit_cast"><code class="language-plaintext highlighter-rouge">std::bit_cast</code></a>, this implies we can alias any object of any type from a <code class="language-plaintext highlighter-rouge">char</code>, <code class="language-plaintext highlighter-rouge">unsigned char</code>, or <code class="language-plaintext highlighter-rouge">signed char</code>, this is called <a href="https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8">the strict aliasing rule</a>.</p>

<p>To illustrate the strict aliasing rule, let’s look at the generated assembly for:</p>

<p><a href="https://godbolt.org/z/M18z53b35"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">A</span> <span class="o">*</span> <span class="n">a</span> <span class="o">=</span> <span class="n">get_A</span><span class="p">();</span>
<span class="n">B</span> <span class="o">*</span> <span class="n">b</span> <span class="o">=</span> <span class="n">get_B</span><span class="p">();</span>

<span class="n">a</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="n">b</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="k">return</span> <span class="n">a</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">;</span>

</code></pre></div></div>

<p>We can see from the example above that the compiler is able to perform a <strong>Dead-Load Optimization</strong> on the expression <code class="language-plaintext highlighter-rouge">a-&gt;value</code> and just assumes the value remains 6, which wouldn’t have been possible if <code class="language-plaintext highlighter-rouge">a</code> could alias <code class="language-plaintext highlighter-rouge">b</code>.</p>

<p>However, if we <strong>really</strong>, <strong>really</strong>, needed to alias both types, we could use the strangely-named function <a href="https://en.cppreference.com/w/cpp/utility/launder"><code class="language-plaintext highlighter-rouge">std::launder</code></a> which would interfere with the compiler’s reachability analysis.</p>

<p><a href="https://godbolt.org/z/8rM6YbM75"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">A</span><span class="o">*</span> <span class="n">a</span> <span class="o">=</span> <span class="n">get_A</span><span class="p">();</span>
<span class="n">B</span><span class="o">*</span> <span class="n">b</span> <span class="o">=</span> <span class="n">get_B</span><span class="p">();</span>
<span class="n">B</span><span class="o">*</span> <span class="n">a_b</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">launder</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span><span class="p">((</span><span class="n">B</span><span class="o">*</span><span class="p">)</span><span class="n">a</span><span class="p">);</span>
<span class="n">a_b</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="n">b</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="k">return</span> <span class="n">a</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">;</span>
</code></pre></div></div>

<p>From the generated assembly, the compiler is forced to perform the redundant load from <code class="language-plaintext highlighter-rouge">a_b</code>, because it <em>could</em> be an alias of <code class="language-plaintext highlighter-rouge">b</code> because it’s origin has been hidden by <code class="language-plaintext highlighter-rouge">std::launder</code>. Which is just like laundering money, hence, the name <code class="language-plaintext highlighter-rouge">:)</code>.</p>

<p><strong>NOTE</strong>: use of <code class="language-plaintext highlighter-rouge">std::launder</code> here is undefined behavior as no object of type <code class="language-plaintext highlighter-rouge">B</code> exists nor was constructed at address <code class="language-plaintext highlighter-rouge">a</code>.</p>

<p>Some languages/dialects have a more aggressive form of this aliasing optimization/rule around mutability and aliasing, i.e. Rust’s mutable reference (<code class="language-plaintext highlighter-rouge">&amp; mut</code>) and <a href="https://github.com/seanbaxter/circle">Circle’s</a> mutable reference which requires only one mutable reference can be binded to an object at once, Which allow for more controversial and aggressive optimizations even across objects of the same type within a scope.
This is comparable to the non-standard <a href="https://en.cppreference.com/w/c/language/restrict"><code class="language-plaintext highlighter-rouge">restrict</code></a> qualifier (GCC/Clang: <a href="https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gcc/Restricted-Pointers.html"><code class="language-plaintext highlighter-rouge">__restrict__</code></a>, and MSVC: <a href="https://learn.microsoft.com/en-us/cpp/cpp/extension-restrict?view=msvc-170"><code class="language-plaintext highlighter-rouge">__restrict</code></a>).</p>

<p>To illustrate:</p>

<p><a href="https://godbolt.org/z/ahd6xT8Gx"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">fn</span><span class="p">(</span><span class="n">A</span><span class="o">*</span> <span class="n">a1</span><span class="p">,</span> <span class="n">A</span><span class="o">*</span> <span class="n">a2</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">a1</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
    <span class="n">a2</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">a1</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As we said earlier, <code class="language-plaintext highlighter-rouge">a1</code> could alias/overlap with <code class="language-plaintext highlighter-rouge">a2</code> since they are the same type and there are no restrictions around mutability even within the same types, therefore the read expression <code class="language-plaintext highlighter-rouge">a1-&gt;value</code> would not optimized and we would still need to load the value, which would be redundant if we can ascertain that the objects do not in fact alias/overlap. Whilst the effect of this would likely go unnoticed on small objects, it would be noticeable on an array of multiple elements due to the data dependency and cause a drastic slowdown.</p>

<p>To optimize this we would use the <code class="language-plaintext highlighter-rouge">restrict</code> attribute, which implies objects with the attribute/qualifier do not alias other objects within that scope.</p>

<p><a href="https://godbolt.org/z/TK94KjTjx"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">fn</span><span class="p">(</span><span class="n">A</span><span class="o">*</span> <span class="n">RESTRICT</span> <span class="n">a1</span><span class="p">,</span> <span class="n">A</span><span class="o">*</span> <span class="n">RESTRICT</span> <span class="n">a2</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">a1</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
    <span class="n">a2</span><span class="o">-&gt;</span><span class="n">value</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">a1</span><span class="o">-&gt;</span><span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="unions">Unions</h4>

<p>Whilst most “modern C++” codebases would outright ban unions due to the difficulty of their constraints or how easy it is to create bugs with them, they remain an essential component of many data structures like <code class="language-plaintext highlighter-rouge">Option&lt;T&gt;</code>, <code class="language-plaintext highlighter-rouge">Result&lt;T, E&gt;</code>.</p>

<p>Unions are used in scenarios where one of multiple objects can exist at a location. Effectively giving room to constrained object dynamism/polymorphism.</p>

<p>Given only one object can exist at a union’s address, the Object lifetime contracts still apply, violations of which would lead to undefined behavior:</p>

<ul>
  <li>At least one of the specified variants must exist in the union</li>
  <li>Any accessed object must have been constructed</li>
  <li>Only one object must exist or be constructed in the union at a point in time, for another object to be constructed in the union, the previously constructed object must first have been destroyed.</li>
</ul>

<p>Even though the variant types in the Union are possibly aliasing, the strict aliasing rules still apply to them, i.e. variant type <code class="language-plaintext highlighter-rouge">A</code> can not alias distinct variant type <code class="language-plaintext highlighter-rouge">B</code>.</p>

<p>i.e.:</p>

<p><a href="https://godbolt.org/z/jYMozMnTx"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">union</span> <span class="n">Which</span> <span class="p">{</span>
    <span class="kt">char</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">Cat</span> <span class="n">cat</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">void</span> <span class="n">react</span><span class="p">(</span><span class="n">Animal</span><span class="o">*</span> <span class="n">a</span><span class="p">)</span> <span class="p">{</span> <span class="n">a</span><span class="o">-&gt;</span><span class="n">react</span><span class="p">();</span> <span class="p">}</span>

<span class="n">Which</span> <span class="n">w</span><span class="p">;</span>  <span class="c1">// only c is initialized</span>
<span class="n">react</span><span class="p">(</span><span class="o">&amp;</span><span class="n">w</span><span class="p">.</span><span class="n">cat</span><span class="p">);</span>  <span class="c1">// SISGSEGV because we accessed `cat` without initializing it</span>

</code></pre></div></div>

<p>To fix:</p>

<p><a href="https://godbolt.org/z/7G8s7vTP9"><em>Godbolt</em></a></p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Which</span> <span class="n">w</span><span class="p">;</span>  <span class="c1">// only c is initialized</span>
<span class="c1">// w.c.~char() - trivial, but char doesn't have a destructor</span>
<span class="k">new</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">w</span><span class="p">.</span><span class="n">cat</span><span class="p">)</span> <span class="n">Cat</span><span class="p">{};</span>  <span class="c1">// now cat is initialized, we can access it</span>
<span class="n">react</span><span class="p">(</span><span class="o">&amp;</span><span class="n">w</span><span class="p">.</span><span class="n">cat</span><span class="p">);</span>       <span class="c1">// purr...</span>
</code></pre></div></div>

<p>As you can see in the example above, we can’t simply pretend to use the union’s other variant, we need to maintain the object lifecycle, by first deleting <code class="language-plaintext highlighter-rouge">c</code> (trivial in this case, so no-op), then constructing <code class="language-plaintext highlighter-rouge">cat</code> using <code class="language-plaintext highlighter-rouge">placement new</code> (non-trivial) which would solve the UB by initializing the v-table for the <code class="language-plaintext highlighter-rouge">Cat</code> object.</p>

<p>This is a common footgun for C developers thinking C++ unions function similarly to C’s.
Also, note that if the union contains non-trivial types, the construction, destruction, assignment, and move operations, need to be manually and explicitly implemented.</p>

<h4 id="stdaligned_storage-deprecated-in-c-23"><code class="language-plaintext highlighter-rouge">std::aligned_storage</code> (deprecated in C++ 23)</h4>

<p>Aligned Storage is meant to be a byte-wise representation of an object, with the object’s lifetime context managed externally or determined by an external source of truth, thus still requiring the represented object’s lifetime to be managed explicitly and correctly by the user, they work similar to unions but have the caveat that they are untyped.</p>

<p>Aligned storage is commonly used for implementing container types, specifically when containing both initialized and uninitialized objects, i.e. Open-Addressing (Linear-Probing Hashmaps), (ECS) Sparse Sets, Static-Capacity Vectors, Stack-allocated vectors, pre-allocated/bump/arena allocators.</p>

<p><strong>NOTE</strong>: <code class="language-plaintext highlighter-rouge">std::aligned_storage</code> was <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1413r3.pdf">deprecated in C++23 (P1413R3)</a></p>

<h4 id="optiont-stdoptionalt"><code class="language-plaintext highlighter-rouge">Option&lt;T&gt;</code> (<code class="language-plaintext highlighter-rouge">std::optional&lt;T&gt;</code>)</h4>

<p><code class="language-plaintext highlighter-rouge">Option&lt;T&gt;</code> implies an object of type <code class="language-plaintext highlighter-rouge">T</code> may or may not exist, this means the object is either initialized or not initialized at the placement address and its existence is recognized by a discriminating enum/boolean.
Implementing <code class="language-plaintext highlighter-rouge">Option&lt;T&gt;</code> would require that the lifecycle of the value type <code class="language-plaintext highlighter-rouge">T</code> is maintained correctly. i.e. the number of constructions is same as the number of destructions, the object’s constructor is called before being regarded as existing in the <code class="language-plaintext highlighter-rouge">Option</code>.</p>

<h4 id="resultt-e-stdexpectedt-e"><code class="language-plaintext highlighter-rouge">Result&lt;T, E&gt;</code> (<code class="language-plaintext highlighter-rouge">std::expected&lt;T, E&gt;</code>)</h4>

<p><code class="language-plaintext highlighter-rouge">Result&lt;T, E&gt;</code> implies an object of type <code class="language-plaintext highlighter-rouge">T</code> or type <code class="language-plaintext highlighter-rouge">E</code> exists at the placement address of the <code class="language-plaintext highlighter-rouge">Result</code>, it is discriminated by an enum or boolean value.
Just like <code class="language-plaintext highlighter-rouge">Option&lt;T&gt;</code>, <code class="language-plaintext highlighter-rouge">Result&lt;T, E&gt;</code> maintains the lifecycle of the value type <code class="language-plaintext highlighter-rouge">T</code> and <code class="language-plaintext highlighter-rouge">E</code>.</p>

<h4 id="trivial-relocation">Trivial Relocation</h4>

<p>Trivial relocation is an upcoming C++ 26 Feature I’m most excited about that further extends the C++ object lifecycle and gives room for further optimizations.</p>

<p>Relocation is a combination of move from the source object to the uninitialized destination and destruction of the object representation left in the source (<em>destructive move<sup>TM</sup></em>).</p>

<p>i.e:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">relocate</span><span class="p">(</span><span class="n">A</span> <span class="o">*</span> <span class="n">src</span><span class="p">,</span> <span class="n">A</span> <span class="o">*</span> <span class="n">dst</span><span class="p">){</span>
    <span class="k">new</span> <span class="p">(</span><span class="n">dst</span><span class="p">)</span> <span class="n">A</span><span class="p">{</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="o">*</span><span class="n">src</span><span class="p">)</span> <span class="p">};</span>
    <span class="n">src</span><span class="o">-&gt;~</span><span class="n">A</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Trivial relocation implies the object can be safely moved from one memory address to another uninitialized memory address without invoking the object’s move constructor and destructor, essentially capturing the “move to destination and destroy source” operation. This means we can instead use a bitewise copy, typically via <code class="language-plaintext highlighter-rouge">memcpy</code> or <code class="language-plaintext highlighter-rouge">memmove</code>, essentially being “trivial”, as long as we don’t treat the source memory address as containing a valid object after the relocation.</p>

<p>i.e:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">trivial_relocate</span><span class="p">(</span><span class="n">A</span> <span class="o">*</span> <span class="n">src</span><span class="p">,</span> <span class="n">A</span> <span class="o">*</span> <span class="n">dst</span><span class="p">){</span>
    <span class="n">memcpy</span><span class="p">(</span><span class="n">dst</span><span class="p">,</span> <span class="n">src</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">A</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Note that trivial relocation doesn’t always imply the move constructor and destructors are trivial.</p>

<p>i.e:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">MyStr</span> <span class="p">{</span>
    <span class="kt">char</span><span class="o">*</span> <span class="n">data_</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">;</span>
    <span class="kt">size_t</span> <span class="n">size_</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">MyStr</span><span class="p">()</span> <span class="p">{}</span>
    <span class="n">MyStr</span><span class="p">(</span><span class="kt">char</span> <span class="k">const</span><span class="o">*</span> <span class="n">data</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">num</span><span class="p">)</span> <span class="o">:</span> <span class="n">data_</span><span class="p">{(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="n">num</span><span class="p">)},</span> <span class="n">size_</span><span class="p">{</span><span class="n">num</span><span class="p">}</span> <span class="p">{</span> <span class="n">memcpy</span><span class="p">(</span><span class="n">data_</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">num</span><span class="p">);</span>  <span class="p">}</span>
    <span class="n">MyStr</span><span class="p">(</span><span class="n">MyStr</span> <span class="k">const</span><span class="o">&amp;</span><span class="p">)</span> <span class="o">=</span> <span class="k">delete</span><span class="p">;</span>
    <span class="n">MyStr</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="n">MyStr</span><span class="o">&amp;&amp;</span><span class="p">)</span> <span class="o">=</span> <span class="k">delete</span><span class="p">;</span>
    <span class="n">MyStr</span><span class="o">&amp;</span> <span class="k">operator</span><span class="o">=</span><span class="p">(</span><span class="n">MyStr</span> <span class="k">const</span><span class="o">&amp;</span><span class="p">)</span> <span class="o">=</span> <span class="k">delete</span><span class="p">;</span>
    <span class="n">MyStr</span><span class="p">(</span><span class="n">MyStr</span><span class="o">&amp;&amp;</span> <span class="n">a</span><span class="p">)</span> <span class="o">:</span> <span class="n">data_</span><span class="p">{</span><span class="n">a</span><span class="p">.</span><span class="n">data_</span><span class="p">},</span> <span class="n">size_</span><span class="p">{</span><span class="n">a</span><span class="p">.</span><span class="n">size_</span><span class="p">}</span> <span class="p">{</span>
        <span class="n">a</span><span class="p">.</span><span class="n">data_</span> <span class="o">=</span> <span class="nb">nullptr</span><span class="p">;</span>
        <span class="n">a</span><span class="p">.</span><span class="n">size_</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="o">~</span><span class="n">MyStr</span><span class="p">()</span> <span class="p">{</span> <span class="n">free</span><span class="p">(</span><span class="n">data</span><span class="p">);</span> <span class="p">}</span>
<span class="p">};</span>

</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">MyStr</code> like many container types don’t have trivial move constructors and destructors, but their object representation can be trivially relocated.</p>

<p>For small locally contained objects, non-trivial-relocation may not affect performance much as the compiler would typically be able to optimize the code generated by the move constructor and destructor, but for implementing generic container types like <code class="language-plaintext highlighter-rouge">std::vector</code> where a large number of these objects are frequently shifted around (i.e. during <code class="language-plaintext highlighter-rouge">push_back</code>, <code class="language-plaintext highlighter-rouge">insert</code>, move of elements from one container to another), trivial relocation (<code class="language-plaintext highlighter-rouge">memcpy</code>/<code class="language-plaintext highlighter-rouge">memmove</code>) would perform better than executing the non-trivial move constructor and destructor that would produce redundant operations, like the setting of <code class="language-plaintext highlighter-rouge">MyStr::num_</code> to <code class="language-plaintext highlighter-rouge">nullptr</code> and <code class="language-plaintext highlighter-rouge">MyStr::size_</code> to <code class="language-plaintext highlighter-rouge">0</code> (as in <code class="language-plaintext highlighter-rouge">std::vector&lt;MyStr&gt;</code> by <code class="language-plaintext highlighter-rouge">MyStr::MyStr(Mystr &amp;&amp;)</code>). This is a consequence of the C++ object model requiring move constructors to leave the source object in a <em>valid<sup>TM</sup></em> but <em>unspecified</em> state for the destructor to still run correctly.</p>

<p>Also note that if your allocator supports <code class="language-plaintext highlighter-rouge">realloc</code>, trivial relocations means <code class="language-plaintext highlighter-rouge">grow</code>‘ing your <code class="language-plaintext highlighter-rouge">vector</code> type’s capacity could be collapsed into a zero-cost <code class="language-plaintext highlighter-rouge">realloc</code> (the Operating System would often just need to extend the allocation’s entry if there’s enough space within the page) rather than allocating a new separate memory, moving the objects to that memory, destroying the residual objects in the source memory and then free-ing the source memory.</p>

<p>Trivial relocation would extend our C++ object lifecycle model to:</p>

<pre><code class="language-txt">  allocate placement memory
             ||
             ||
             ||   =============================&gt; relocate object
             ||   ||                                   ||
             ||   ||               ============        ||
             \/   ||               ||        ||        ||
====&gt;  construct object ===&gt; assign object &lt;===        ||
||           ||                    ||                  ||
||           \/                    ||                  ||
====== destruct object  &lt;============                  ||
             ||                                        ||
             \/                                        ||
 deallocate placement memory &lt;===========================
</code></pre>

<ul>
  <li><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2786r0.pdf">P2786R0: Trivial relocatability options,
Proposal for an alternative approach to trivial relocatability</a></li>
  <li><a href="https://quuxplusone.github.io/blog/2023/03/03/relocate-algorithm-design/">STL algorithms for trivial relocation</a></li>
  <li><a href="https://www.youtube.com/watch?v=DZ0maTWD_9g">C++ Trivial Relocation Through Time - Mungo Gill - ACCU 2023</a></li>
</ul>]]></content><author><name>Basit Ayantunde</name><email>basitayde@gmail.com</email></author><category term="c++" /><category term="RAII" /><category term="memory" /><summary type="html"><![CDATA[An analysis of the C++ Object Lifecycle]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://basit.pro/cpp-object-lifecycle/omen.jpg" /><media:content medium="image" url="https://basit.pro/cpp-object-lifecycle/omen.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>