<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wang - C++ Developer</title>
    <description>The latest articles on DEV Community by Wang - C++ Developer (@legacycpp).</description>
    <link>https://dev.to/legacycpp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3830024%2Ff4f48e4a-2672-44a3-8ee0-76063145b056.png</url>
      <title>DEV Community: Wang - C++ Developer</title>
      <link>https://dev.to/legacycpp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/legacycpp"/>
    <language>en</language>
    <item>
      <title>Crash Patterns Overview: A Practical, Symptom‑First Guide to Debugging C++ Crashes</title>
      <dc:creator>Wang - C++ Developer</dc:creator>
      <pubDate>Thu, 14 May 2026 14:57:56 +0000</pubDate>
      <link>https://dev.to/legacycpp/crash-patterns-overview-a-practical-symptom-first-guide-to-debugging-c-crashes-27k</link>
      <guid>https://dev.to/legacycpp/crash-patterns-overview-a-practical-symptom-first-guide-to-debugging-c-crashes-27k</guid>
      <description>&lt;p&gt;Debugging C++ crashes is not guesswork. It’s pattern recognition.&lt;br&gt;&lt;br&gt;
After decades of debugging production systems, one truth becomes obvious: &lt;strong&gt;crashes follow repeatable patterns&lt;/strong&gt; — not because the bugs are simple, but because the ways C++ programs fail are consistent.&lt;/p&gt;

&lt;p&gt;This article introduces a practical, &lt;strong&gt;two‑layer model&lt;/strong&gt; for understanding crashes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Symptom Buckets&lt;/strong&gt; — what you can observe immediately
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crash Patterns&lt;/strong&gt; — what those symptoms usually mean
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This model is the foundation of the entire crash‑analysis series.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;Contents&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why a Symptom‑First Model&lt;/li&gt;
&lt;li&gt;The Five Symptom Buckets (S1–S5)&lt;/li&gt;
&lt;li&gt;The Ten Crash Patterns&lt;/li&gt;
&lt;li&gt;The Debugging Workflow&lt;/li&gt;
&lt;li&gt;What This Model Enables for Teams&lt;/li&gt;
&lt;li&gt;What’s Next in the Series&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  ⭐ &lt;strong&gt;Why a Symptom‑First Model&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When a C++ program crashes, you never begin with the root cause.&lt;br&gt;&lt;br&gt;
You begin with the &lt;strong&gt;raw signals&lt;/strong&gt; the system gives you at the moment of failure.&lt;/p&gt;

&lt;p&gt;These signals are limited, messy, and often incomplete — but they are consistent enough that, over decades of debugging, engineers have learned to group them into &lt;strong&gt;five repeatable categories&lt;/strong&gt;, which we call &lt;strong&gt;Symptom Buckets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These buckets come directly from the only things you can reliably observe when a crash happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Where the crash occurred?&lt;/strong&gt;  your code, allocator, thread library, kernel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What the call stack looks like?&lt;/strong&gt;  clean, corrupted, missing frames, nonsense addresses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What the allocator reports?&lt;/strong&gt;  invalid free, corrupted chunk, double free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What the threads are doing?&lt;/strong&gt;  running, blocked, deadlocked, spinning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What sanitizers report?&lt;/strong&gt;  (only when running with sanitizers enabled — ASan/TSAN/UBSan/Valgrind)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the first clues — and at the moment of a crash, they’re all you have. Everything else (patterns, root causes, fixes) comes later.&lt;/p&gt;

&lt;p&gt;A symptom‑first model mirrors how real debugging works in production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Observe the symptom&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classify it into a Symptom Bucket&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infer the likely crash patterns&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose the right tools&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identify the Root Cause&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fix the underlying code&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the workflow used by senior engineers in real systems.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⭐ &lt;strong&gt;Layer 1 — Symptom Buckets (Start Here)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Based on the symptoms you observe at the moment of a crash, you can classify the failure into one of five buckets.&lt;br&gt;&lt;br&gt;
Each bucket represents a distinct observable behavior — the first clue in the debugging workflow.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;S1 — Clean Backtrace Crashes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptoms&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backtrace is readable and complete
&lt;/li&gt;
&lt;li&gt;Frames make sense
&lt;/li&gt;
&lt;li&gt;Crash occurs inside your code
&lt;/li&gt;
&lt;li&gt;Program counter points to a valid instruction
&lt;/li&gt;
&lt;li&gt;No signs of stack corruption
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Likely patterns&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Null pointer dereference
&lt;/li&gt;
&lt;li&gt;Uninitialized memory
&lt;/li&gt;
&lt;li&gt;Simple boundary error
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;S2 — Crashes in malloc/free/new/delete&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptoms&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backtrace ends inside allocator functions
&lt;/li&gt;
&lt;li&gt;Allocator reports “invalid pointer”, “double free”, “corrupted chunk”
&lt;/li&gt;
&lt;li&gt;Crash happens during allocation or deallocation
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Likely patterns&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use‑after‑free
&lt;/li&gt;
&lt;li&gt;Double free
&lt;/li&gt;
&lt;li&gt;Heap corruption
&lt;/li&gt;
&lt;li&gt;Boundary error on heap buffer
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;S3 — Broken or Nonsensical Backtrace&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptoms&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gdb shows garbage frames
&lt;/li&gt;
&lt;li&gt;Return addresses look invalid
&lt;/li&gt;
&lt;li&gt;Stack unwinding fails
&lt;/li&gt;
&lt;li&gt;Backtrace jumps into unrelated modules
&lt;/li&gt;
&lt;li&gt;Stepping behaves unpredictably
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Likely patterns&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stack corruption
&lt;/li&gt;
&lt;li&gt;Severe boundary error
&lt;/li&gt;
&lt;li&gt;ABI mismatch
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;S4 — Process Frozen (No Crash)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptoms&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No core dump
&lt;/li&gt;
&lt;li&gt;CPU usage low or zero
&lt;/li&gt;
&lt;li&gt;Threads blocked
&lt;/li&gt;
&lt;li&gt;Program stops making progress
&lt;/li&gt;
&lt;li&gt;gdb shows threads waiting on locks
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Likely patterns&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deadlock
&lt;/li&gt;
&lt;li&gt;Livelock
&lt;/li&gt;
&lt;li&gt;Waiting forever
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;S5 — Sanitizer Reports (ASan/TSAN/UBSan/Valgrind)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptoms&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
(Only when running with sanitizers enabled)  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ASan: heap-use-after-free, stack-buffer-overflow
&lt;/li&gt;
&lt;li&gt;TSAN: data race
&lt;/li&gt;
&lt;li&gt;UBSan: undefined behavior
&lt;/li&gt;
&lt;li&gt;Valgrind: invalid read/write, uninitialized value
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Likely patterns&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory lifetime errors
&lt;/li&gt;
&lt;li&gt;Boundary errors
&lt;/li&gt;
&lt;li&gt;Concurrency errors
&lt;/li&gt;
&lt;li&gt;Initialization errors
&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  ⭐ &lt;strong&gt;Layer 2 — Crash Patterns (What the Symptoms Suggest)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;These are the &lt;strong&gt;10 recurring crash patterns&lt;/strong&gt; seen in real C++ systems.&lt;br&gt;
Each pattern describes a type of failure. Deep‑dive articles will follow later.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Memory Lifetime Errors&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;1. Null Pointer Dereference&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Accessing memory through a pointer that is &lt;code&gt;nullptr&lt;/code&gt;.&lt;br&gt;
Often caused by missing initialization or failed allocation.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;2. Use‑After‑Free (UAF)&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Accessing memory after it has been freed.&lt;br&gt;
The pointer still “looks valid,” but the memory no longer belongs to you.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;3. Double Free / Invalid Free&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Freeing the same memory twice, or freeing memory never allocated. This corrupts allocator metadata and often crashes inside &lt;code&gt;free()&lt;/code&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Memory Boundary Errors&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;4. Boundary / Off‑By‑One Error&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Reading or writing just outside the valid range of a buffer.&lt;br&gt;
Often subtle: wrong index, wrong size, or one extra iteration.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;5. Stack Corruption&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Writing past a stack buffer and overwriting the return address or saved registers.&lt;br&gt;
This breaks stack unwinding and produces nonsensical backtraces.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;6. Heap Corruption&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Writing past a heap allocation and damaging allocator metadata.&lt;br&gt;
Crashes usually appear later during &lt;code&gt;malloc()&lt;/code&gt; or &lt;code&gt;free()&lt;/code&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Concurrency Errors&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;7. Data Race&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Two threads access the same memory without proper synchronization.&lt;br&gt;
Leads to unpredictable behavior and rare crashes.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;8. Deadlock / Livelock&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Threads block each other forever (deadlock) or keep running without progress (livelock).&lt;br&gt;
The program freezes instead of crashing.&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;ABI / Layout Errors&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;9. ABI Mismatch&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Different modules disagree on struct layout, calling conventions, or compiler settings.&lt;br&gt;
Objects appear corrupted even though the code “looks correct.”&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Initialization Errors&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;10. Uninitialized Memory&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Using a variable or buffer before assigning a value.&lt;br&gt;
Debug builds often hide it; release builds expose it.&lt;/p&gt;


&lt;h2&gt;
  
  
  ⭐ &lt;strong&gt;The Debugging Workflow (The Core of This Series)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the model you will learn to apply:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symptom → Pattern → Tools → Fix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Crash in &lt;code&gt;free()&lt;/code&gt; → S2&lt;br&gt;&lt;br&gt;
Likely UAF or heap corruption → Pattern&lt;br&gt;&lt;br&gt;
Run ASan → Tools&lt;br&gt;&lt;br&gt;
Fix ownership or indexing → Fix  &lt;/p&gt;

&lt;p&gt;This workflow is repeatable, reliable, and works in real production systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────┐
│ 1. Observe the Symptom                                   │
│    (backtrace, allocator message, thread state, sanitizer)│
└──────────────────────────────────────────────────────────┘
                     ▼
┌──────────────────────────────────────────────────────────┐
│ 2. Classify into a Symptom Bucket (S1–S5)                │
│    Clean backtrace? Allocator crash? Broken stack? Freeze?│
│    Sanitizer report?                                      │
└──────────────────────────────────────────────────────────┘
                     ▼
┌──────────────────────────────────────────────────────────┐
│ 3. Map to Likely Crash Patterns (10 patterns)             │
│    UAF? Double free? Boundary error? Data race? ABI issue?│
└──────────────────────────────────────────────────────────┘
                     ▼
┌──────────────────────────────────────────────────────────┐
│ 4. Choose the Right Tools                                 │
│    gdb, ASan/TSAN, Valgrind, logging, core dumps, traces  │
└──────────────────────────────────────────────────────────┘
                     ▼
┌──────────────────────────────────────────────────────────┐
│ 5. Identify the Root Cause                                │
│    Ownership? Boundary? Concurrency? Layout? Init?        │
└──────────────────────────────────────────────────────────┘
                     ▼
┌──────────────────────────────────────────────────────────┐
│ 6. Apply the Fix                                          │
│    Correct lifetime, fix indexing, add locks, fix ABI,    │
│    initialize variables, redesign unsafe code paths       │
└──────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⭐ &lt;strong&gt;What This Model Enables for Teams&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A shared debugging framework:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reduces time‑to‑root‑cause
&lt;/li&gt;
&lt;li&gt;avoids chasing noise
&lt;/li&gt;
&lt;li&gt;makes debugging teachable
&lt;/li&gt;
&lt;li&gt;creates shared vocabulary
&lt;/li&gt;
&lt;li&gt;prevents “hero debugging” culture
&lt;/li&gt;
&lt;li&gt;scales across large systems
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not just a technique — This shared model turns debugging from an individual skill into a repeatable team capability.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⭐ &lt;strong&gt;What’s Next&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Next article:&lt;br&gt;&lt;br&gt;
👉 &lt;strong&gt;S1 — Clean Backtrace Crashes&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
How to debug the “easy mode” crashes: null pointers, uninitialized memory, simple OOB.&lt;/p&gt;

&lt;p&gt;Then:&lt;br&gt;&lt;br&gt;
👉 S2, S3, S4, S5&lt;br&gt;&lt;br&gt;
👉 Pattern deep‑dives&lt;br&gt;&lt;br&gt;
👉 Advanced debugging topics  &lt;/p&gt;

&lt;p&gt;Each article will include real crash examples, tools, and step‑by‑step workflows you can apply immediately.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://lnkd.in/ekhzzfum" rel="noopener noreferrer"&gt;https://lnkd.in/ekhzzfum&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>legacy</category>
      <category>crash</category>
      <category>gdb</category>
    </item>
    <item>
      <title>Finding Memory Leaks in Legacy C++ Applications with Valgrind</title>
      <dc:creator>Wang - C++ Developer</dc:creator>
      <pubDate>Wed, 06 May 2026 18:43:51 +0000</pubDate>
      <link>https://dev.to/legacycpp/finding-memory-leaks-in-legacy-c-applications-with-valgrind-254i</link>
      <guid>https://dev.to/legacycpp/finding-memory-leaks-in-legacy-c-applications-with-valgrind-254i</guid>
      <description>&lt;p&gt;Legacy C++ services don't crash — they slowly bleed memory until someone restarts them at 3 AM.&lt;/p&gt;

&lt;p&gt;If you've inherited a 20‑year‑old codebase with mysterious memory growth, this guide is for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can't fix a leak if you can't reproduce.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is your complete, production‑focused Valgrind investigation playbook.&lt;br&gt;
It's based on real systems, real leaks, and real debugging pain.&lt;/p&gt;


&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Workflow&lt;/li&gt;
&lt;li&gt;Step 1 — Reproduce the Leak&lt;/li&gt;
&lt;li&gt;Step 2 — Static Analysis&lt;/li&gt;
&lt;li&gt;Step 3 — Compile for Valgrind&lt;/li&gt;
&lt;li&gt;Step 4 — Run Valgrind&lt;/li&gt;
&lt;li&gt;Step 5 — Understand Valgrind's Leak Types&lt;/li&gt;
&lt;li&gt;Step 6 — Capture the Stack Trace&lt;/li&gt;
&lt;li&gt;Step 7 — Optional Regression Test&lt;/li&gt;
&lt;li&gt;Quick Reference&lt;/li&gt;
&lt;li&gt;Real‑World Example&lt;/li&gt;
&lt;li&gt;The Golden Rule&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The Workflow
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Leak Trigger] → [Static Analysis] → [Compile Debug Build]
        ↓
   [Run Valgrind] → [Interpret Leak Types] → [Stack Trace]
        ↓
     [Regression Test]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1 — Reproduce the Leak
&lt;/h2&gt;

&lt;p&gt;You cannot find a leak if you cannot trigger it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Measure memory growth
&lt;/h3&gt;

&lt;p&gt;use the following script to track the total memory of your application used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;pgrep your_service&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;pmap &lt;span class="nv"&gt;$PID&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;total | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $2}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;sleep &lt;/span&gt;60
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Interpretation:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linear growth&lt;/td&gt;
&lt;td&gt;Per‑operation leak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Step‑function growth&lt;/td&gt;
&lt;td&gt;Specific trigger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No growth&lt;/td&gt;
&lt;td&gt;Wrong hypothesis&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Find the minimum trigger
&lt;/h3&gt;

&lt;p&gt;Your goal: &lt;strong&gt;reproduce the leak in under 10 minutes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Valgrind slows execution by 20–50×&lt;/li&gt;
&lt;li&gt;A 10‑minute trigger becomes 3–8 hours&lt;/li&gt;
&lt;li&gt;A 1‑hour trigger becomes 2–5 days&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; If your trigger is too slow, Valgrind becomes unusable.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 2 — Static Analysis (5 minutes, zero runtime cost)
&lt;/h2&gt;

&lt;p&gt;Before running anything, let the compiler find the obvious issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clang Static Analyzer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scan-build make
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for &lt;strong&gt;"Memory leak"&lt;/strong&gt; warnings (ignore "Potential leak").&lt;/p&gt;

&lt;h3&gt;
  
  
  clang‑tidy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clang-tidy legacy_file.cpp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--checks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'-*,clang-analyzer-*,cppcoreguidelines-owning-memory'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Finds:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;new&lt;/code&gt; without &lt;code&gt;delete&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;malloc&lt;/code&gt; without &lt;code&gt;free&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Raw owning pointers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Misses:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cycles&lt;/li&gt;
&lt;li&gt;Third‑party leaks&lt;/li&gt;
&lt;li&gt;Runtime‑dependent leaks&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; Static analysis gives you free wins before you even run the program.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 3 — Compile for Valgrind
&lt;/h2&gt;

&lt;p&gt;Valgrind is useless without debug symbols. So first thing you should do is to compile the whole application with debug flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-g3&lt;/span&gt; &lt;span class="nt"&gt;-O0&lt;/span&gt; &lt;span class="nt"&gt;-fno-omit-frame-pointer&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; your_service your_service.cpp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-g3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full debug info&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-O0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clean stack frames&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-fno-omit-frame-pointer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reliable backtraces&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; Without debug symbols, Valgrind can't show you file/line numbers.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 4 — Run Valgrind
&lt;/h2&gt;

&lt;p&gt;Run only the trigger you identified in Step 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;valgrind &lt;span class="nt"&gt;--leak-check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;full &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="nt"&gt;--show-leak-kinds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;definite,indirect &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="nt"&gt;--track-origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="nt"&gt;--log-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;valgrind_out.txt &lt;span class="se"&gt;\&lt;/span&gt;
         ./your_service &lt;span class="nt"&gt;--run-trigger&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  For long‑running services
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;vgdb&lt;/code&gt; to inspect leaks mid‑run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;valgrind &lt;span class="nt"&gt;--vgdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="nt"&gt;--vgdb-error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nt"&gt;--leak-check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;full ./your_service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vgdb leak_check full definite indirect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; You don't need to wait hours — you can inspect leaks while running.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 5 — Understand Valgrind's Leak Types
&lt;/h2&gt;

&lt;p&gt;After the run, Valgrind will give you a report about memory lost in valgrind_out.txt. Example summary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;definitely lost: 1,024 bytes
indirectly lost: 6,144 bytes
possibly lost: 0 bytes
still reachable: 45,000 bytes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What each type means
&lt;/h3&gt;

&lt;p&gt;Valgrind gives the following types of memory lost. Based on the types, you decides your action.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;definitely lost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real leak&lt;/td&gt;
&lt;td&gt;Fix first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;indirectly lost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Child of a lost block&lt;/td&gt;
&lt;td&gt;Fix parent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;possibly lost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pointer arithmetic / corruption&lt;/td&gt;
&lt;td&gt;Investigate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;still reachable&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Globals/statics&lt;/td&gt;
&lt;td&gt;Ignore unless growing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  If "still reachable" grows
&lt;/h3&gt;

&lt;p&gt;Use Massif:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;valgrind &lt;span class="nt"&gt;--tool&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;massif ./your_trigger
ms_print massif.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; "Still reachable" is not a leak — unless it grows.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 6 — Capture the Stack Trace
&lt;/h2&gt;

&lt;p&gt;A real leak looks like the following. With the stack trace and debug symbols, exact source file name and line number will be given. That is where memory is allocated. To fix it, you need to find out why the allocated memory was not released, e.g. delete is only called on one running path. With the trigger, another running path is active.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1,024 bytes in 1 blocks are definitely lost
at operator new
by DatabaseConnection::ExecuteQuery (db_connection.cpp:67)
by CustomerLoader::FetchCustomer (customer_loader.cpp:89)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extract only leak blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-A10&lt;/span&gt; &lt;span class="s2"&gt;"definitely lost"&lt;/span&gt; valgrind_out.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; The stack trace is the map that leads you to the leak.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 7 — Optional Regression Test
&lt;/h2&gt;

&lt;p&gt;Useful when multiple developers touch the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;TEST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LeakTest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConfirmLeakExists&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_current_rss&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;suspect_function&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_current_rss&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;EXPECT_LT&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; Regression tests prevent old leaks from returning.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Basic leak check&lt;/td&gt;
&lt;td&gt;&lt;code&gt;valgrind --leak-check=full ./binary&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Only real leaks&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--show-leak-kinds=definite,indirect&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Save output&lt;/td&gt;
&lt;td&gt;&lt;code&gt;--log-file=leak.log&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check running service&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vgdb leak_check full definite indirect&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heap profiling&lt;/td&gt;
&lt;td&gt;&lt;code&gt;valgrind --tool=massif&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extract leak&lt;/td&gt;
&lt;td&gt;&lt;code&gt;grep -A10 "definitely lost"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Real‑World Example
&lt;/h2&gt;

&lt;p&gt;Imagine a legacy service that loads customers from a database and caches them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The bug
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// customer_loader.h&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomerRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;LoadCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// customer_loader.cpp&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"customer_loader.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"db_connection.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;CustomerRepository&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LoadCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// singleton&lt;/span&gt;
    &lt;span class="n"&gt;ResultSet&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ExecuteQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT id, name FROM customers WHERE id = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// BUG: ResultSet is never deleted&lt;/span&gt;
    &lt;span class="c1"&gt;// delete rs;  // missing&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// caller owns Customer*&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caller code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CustomerRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ... use c ...&lt;/span&gt;

    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// correct&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this looks “fine” because &lt;code&gt;Customer&lt;/code&gt; is deleted.&lt;br&gt;&lt;br&gt;
But &lt;code&gt;ResultSet&lt;/code&gt; is leaked on every call.&lt;/p&gt;


&lt;h3&gt;
  
  
  Valgrind report
&lt;/h3&gt;

&lt;p&gt;You run your request handler under Valgrind:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;valgrind &lt;span class="nt"&gt;--leak-check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;full &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="nt"&gt;--show-leak-kinds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;definite,indirect &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="nt"&gt;--track-origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
         &lt;span class="nt"&gt;--log-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;valgrind_leak.log &lt;span class="se"&gt;\&lt;/span&gt;
         ./service &lt;span class="nt"&gt;--handle-request&lt;/span&gt; 42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Relevant part of the report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;==12345== 128 bytes in 1 blocks are definitely lost in loss record 3 of 5
==12345==    at 0x4C2F1A3: operator new(unsigned long) (vg_replace_malloc.c:422)
==12345==    by 0x401F8B: ResultSet::ResultSet(DBHandle*) (result_set.cpp:27)
==12345==    by 0x4023D1: DatabaseConnection::ExecuteQuery(std::string const&amp;amp;) (db_connection.cpp:88)
==12345==    by 0x4039A4: CustomerRepository::LoadCustomer(int) (customer_loader.cpp:11)
==12345==    by 0x40412F: ProcessRequest(int) (request_handler.cpp:25)
==12345==    by 0x4043C9: main (main.cpp:17)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;“128 bytes in 1 blocks are definitely lost”&lt;/strong&gt; → real leak
&lt;/li&gt;
&lt;li&gt;Allocation happens in &lt;code&gt;ResultSet::ResultSet&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The call chain leads to &lt;code&gt;CustomerRepository::LoadCustomer&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need to know &lt;code&gt;ResultSet&lt;/code&gt; internals—only that you allocated it and never freed it.&lt;/p&gt;




&lt;h3&gt;
  
  
  The fix
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;CustomerRepository&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LoadCustomer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DatabaseConnection&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;ResultSet&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ExecuteQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT id, name FROM customers WHERE id = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// ✅ free on early return&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;rs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;// ✅ free after use&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re‑run Valgrind:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;==12345== HEAP SUMMARY:
==12345==     in use at exit: 0 bytes in 0 blocks
==12345==   total heap usage: 1,234 allocs, 1,234 frees, 98,765 bytes allocated
==12345== 
==12345== All heap blocks were freed -- no leaks are possible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Golden Rule
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Never start fixing until you can reproduce the leak in under 10 minutes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The trigger is your truth.&lt;br&gt;
The stack trace is your map.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>legacy</category>
      <category>valgrind</category>
      <category>clangtidy</category>
    </item>
    <item>
      <title>Debugging Legacy C++ Crashes: Core Dumps, Symbols, addr2line, and GDB Explained</title>
      <dc:creator>Wang - C++ Developer</dc:creator>
      <pubDate>Sun, 26 Apr 2026 16:30:27 +0000</pubDate>
      <link>https://dev.to/legacycpp/debugging-legacy-c-crashes-core-dumps-symbols-addr2line-and-gdb-explained-33fh</link>
      <guid>https://dev.to/legacycpp/debugging-legacy-c-crashes-core-dumps-symbols-addr2line-and-gdb-explained-33fh</guid>
      <description>&lt;p&gt;You're on call. A production C++ service just crashed — no logs, no stack trace, just a dead process and maybe a core file.&lt;/p&gt;

&lt;p&gt;This guide gives you a &lt;strong&gt;clear, repeatable workflow&lt;/strong&gt; to diagnose any crash, even when you're missing debug symbols or working with a stripped legacy binary. Whether you have a core file, a symbol file, an unstripped build, or nothing at all, you will always know the next step.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;Debugging crashes in legacy C++ systems is notoriously difficult because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployments often strip symbols&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Core dumps are disabled in production&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build IDs don’t match&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ASLR shifts memory layouts&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frame pointers are omitted&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Systemd overrides &lt;code&gt;ulimit&lt;/code&gt; settings&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This workflow eliminates guesswork and gives you a deterministic path from &lt;em&gt;crash&lt;/em&gt; to &lt;em&gt;root cause&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Crash Debugging Decision Map
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CRASH
  |
  v
HAVE CORE FILE?
  |-- No --&amp;gt; Enable cores (Path B) → Reproduce crash
  |
  |-- Yes (Path A)
        |
        v
   HAVE DEBUG SYMBOLS?
        |-- Yes --&amp;gt; Debug now (A4)
        |
        |-- No
              |
              v
        HAVE SYMBOL FILE?
              |-- Yes --&amp;gt; Load with -s (A6)
              |
              |-- No
                    |
                    v
        CAN REPRODUCE WITH SYMBOLS?
              |-- Yes --&amp;gt; Rebuild with -g (A7)
              |
              |-- No
                    |
                    v
        HAVE ORIGINAL BUILD?
              |-- Yes --&amp;gt; Map addresses (A8)
              |
              |-- No --&amp;gt; Fallback analysis (A9)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Path A — You Have a Core File
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A1 — Locate the Core File
&lt;/h3&gt;

&lt;p&gt;Common locations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; core&lt;span class="k"&gt;*&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /var/core/
find / &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"core*"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f 2&amp;gt;/dev/null
&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/sys/kernel/core_pattern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you find a core file, continue to &lt;strong&gt;A2&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
If not, jump to &lt;strong&gt;Path B&lt;/strong&gt;.&lt;/p&gt;


&lt;h3&gt;
  
  
  A2 — Identify Which Binary Produced the Core
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;file core
gdb &lt;span class="nt"&gt;-c&lt;/span&gt; core &lt;span class="nt"&gt;-batch&lt;/span&gt; &lt;span class="nt"&gt;-ex&lt;/span&gt; &lt;span class="s2"&gt;"info files"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Confirm that the core file belongs to the binary you intend to debug (path, build, version).&lt;/p&gt;


&lt;h3&gt;
  
  
  A3 — Check Whether the Binary Has Debug Symbols
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;file ./myapp
nm ./myapp | &lt;span class="nb"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;If the binary is &lt;strong&gt;not stripped&lt;/strong&gt; and you see symbol names → go to &lt;strong&gt;A4&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;If it is &lt;strong&gt;stripped&lt;/strong&gt; → go to &lt;strong&gt;A5&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  A4 — Debugging With Symbols (Best Case)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gdb ./myapp core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Useful GDB commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bt full
info threads
thread apply all bt
frame 0
info locals
print var
list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you usually have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The crashing function and line
&lt;/li&gt;
&lt;li&gt;The call stack
&lt;/li&gt;
&lt;li&gt;Local variables and arguments
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  A5 — Binary Is Stripped: Find the Symbol File
&lt;/h3&gt;

&lt;p&gt;In many production setups, the deployed binary is stripped, but symbol files are archived separately.&lt;/p&gt;

&lt;h4&gt;
  
  
  A5.1 — Extract Build ID
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;readelf &lt;span class="nt"&gt;-n&lt;/span&gt; ./myapp | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Build ID"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll get something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build ID: 1234567890abcdef...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  A5.2 — Locate Matching Symbol File
&lt;/h4&gt;

&lt;p&gt;Search your symbol store (example path):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find /symbols &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-exec&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"1234567890abcdef"&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If you find a matching symbol file → go to &lt;strong&gt;A6&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;If not → go to &lt;strong&gt;A7&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  A6 — Debug Using Separate Symbol Files
&lt;/h3&gt;

&lt;p&gt;If your symbol file is &lt;code&gt;myapp.dbg&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gdb &lt;span class="nt"&gt;-s&lt;/span&gt; myapp.dbg &lt;span class="nt"&gt;-e&lt;/span&gt; ./myapp &lt;span class="nt"&gt;-c&lt;/span&gt; core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or recombine into a single unstripped binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eu-unstrip ./myapp myapp.dbg &lt;span class="nt"&gt;-o&lt;/span&gt; myapp.full
gdb ./myapp.full core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use the same commands as in &lt;strong&gt;A4&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  A7 — No Symbol File: Reproduce With Debug Build
&lt;/h3&gt;

&lt;p&gt;If you can rebuild and reproduce the crash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-O0&lt;/span&gt; &lt;span class="nt"&gt;-fno-omit-frame-pointer&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; myapp_debug ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the debug build under the same conditions until it crashes and generates a new core file. Then debug that core with full symbols as in &lt;strong&gt;A4&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you &lt;strong&gt;cannot&lt;/strong&gt; reproduce the crash (e.g., one‑off production incident), continue with &lt;strong&gt;A8&lt;/strong&gt; or &lt;strong&gt;A9&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  A8 — Map Raw Addresses Using an Unstripped Build
&lt;/h3&gt;

&lt;p&gt;If you still have the original unstripped build (or can reconstruct it):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Extract the crash address&lt;/strong&gt; from the core:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   gdb &lt;span class="nt"&gt;-c&lt;/span&gt; core &lt;span class="nt"&gt;-batch&lt;/span&gt; &lt;span class="nt"&gt;-ex&lt;/span&gt; &lt;span class="s2"&gt;"info registers"&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;rip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get the memory map&lt;/strong&gt; of the process:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   gdb &lt;span class="nt"&gt;-c&lt;/span&gt; core &lt;span class="nt"&gt;-batch&lt;/span&gt; &lt;span class="nt"&gt;-ex&lt;/span&gt; &lt;span class="s2"&gt;"info proc mappings"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compute the offset&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   offset = crash_address - base_address_of_binary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Map the offset to source&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   addr2line &lt;span class="nt"&gt;-e&lt;/span&gt; /path/to/unstripped/myapp &lt;span class="nt"&gt;-f&lt;/span&gt; 0xOFFSET
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you the function and line number corresponding to the crash address.&lt;/p&gt;




&lt;h3&gt;
  
  
  A9 — No Symbols, No Reproduction: Fallback Forensics
&lt;/h3&gt;

&lt;p&gt;Even with no symbols and no way to reproduce, you can still extract useful information.&lt;/p&gt;

&lt;h4&gt;
  
  
  Inspect Registers
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gdb &lt;span class="nt"&gt;-c&lt;/span&gt; core &lt;span class="nt"&gt;-batch&lt;/span&gt; &lt;span class="nt"&gt;-ex&lt;/span&gt; &lt;span class="s2"&gt;"info registers"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Null pointers (&lt;code&gt;rax&lt;/code&gt;, &lt;code&gt;rdi&lt;/code&gt;, etc. equal to &lt;code&gt;0x0&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;Suspicious addresses in your binary’s range
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Inspect Instructions Around the Crash
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gdb &lt;span class="nt"&gt;-c&lt;/span&gt; core &lt;span class="nt"&gt;-batch&lt;/span&gt; &lt;span class="nt"&gt;-ex&lt;/span&gt; &lt;span class="s2"&gt;"x/20i &lt;/span&gt;&lt;span class="nv"&gt;$rip&lt;/span&gt;&lt;span class="s2"&gt;-40"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mov    %rax,%rdi
test   %rdi,%rdi
je     &amp;lt;skip&amp;gt;
mov    (%rdi),%rdx   ← crash here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;rdi&lt;/code&gt; is &lt;code&gt;0x0&lt;/code&gt;, you can infer a &lt;strong&gt;null pointer dereference&lt;/strong&gt;, even without symbols.&lt;/p&gt;




&lt;h2&gt;
  
  
  Path B — No Core File Generated
&lt;/h2&gt;

&lt;h3&gt;
  
  
  B1 — Check Core Dump Settings
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ulimit&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/sys/kernel/core_pattern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;ulimit -c&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;, core dumps are disabled for your shell or service.&lt;/p&gt;




&lt;h3&gt;
  
  
  B2 — Enable Core Dumps
&lt;/h3&gt;

&lt;p&gt;Temporary (current shell):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ulimit&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; unlimited
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Permanent (system‑wide):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"* soft core unlimited"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/security/limits.conf
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"* hard core unlimited"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/security/limits.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may need to log out and back in, or restart services.&lt;/p&gt;




&lt;h3&gt;
  
  
  B3 — Set Core File Location
&lt;/h3&gt;

&lt;p&gt;Configure a directory for core files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"/var/core/core.%e.%p.%t"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /proc/sys/kernel/core_pattern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;%e&lt;/code&gt; — executable name
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%p&lt;/code&gt; — PID
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%t&lt;/code&gt; — timestamp
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  B4 — Fix Permissions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /var/core
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;1777 /var/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures any process can write core files there.&lt;/p&gt;




&lt;h3&gt;
  
  
  B5 — Test Core Dump Generation
&lt;/h3&gt;

&lt;p&gt;Create a small crash program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile and run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-g&lt;/span&gt; crash_test.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; crash_test
./crash_test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that a core file appears in &lt;code&gt;/var/core&lt;/code&gt; (or your configured directory).&lt;/p&gt;




&lt;h3&gt;
  
  
  B6 — Rerun the Crashed Application
&lt;/h3&gt;

&lt;p&gt;Now rerun the real application under the same conditions.&lt;br&gt;&lt;br&gt;
When it crashes, it should generate a core file.&lt;/p&gt;

&lt;p&gt;Then return to &lt;strong&gt;Path A&lt;/strong&gt; and continue from &lt;strong&gt;A2&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Core dumps disabled in production (&lt;code&gt;ulimit -c 0&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;Stripped binaries deployed without archiving symbol files
&lt;/li&gt;
&lt;li&gt;Mismatched Build IDs between binary and symbol file
&lt;/li&gt;
&lt;li&gt;ASLR causing incorrect address mapping when computing offsets
&lt;/li&gt;
&lt;li&gt;Missing frame pointers (&lt;code&gt;-fomit-frame-pointer&lt;/code&gt;) breaking backtraces
&lt;/li&gt;
&lt;li&gt;Systemd or other service managers overriding &lt;code&gt;ulimit&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Symbol files not stored or indexed by Build ID
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Quick Reference Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Enable cores&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ulimit -c unlimited&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find cores&lt;/td&gt;
&lt;td&gt;&lt;code&gt;find / -name "core*"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check symbols&lt;/td&gt;
&lt;td&gt;&lt;code&gt;file ./myapp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Get Build ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;readelf -n ./myapp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug with symbols&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gdb -s myapp.dbg -e myapp -c core&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Map address&lt;/td&gt;
&lt;td&gt;&lt;code&gt;addr2line -e myapp -f 0xOFFSET&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check core pattern&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cat /proc/sys/kernel/core_pattern&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Pro Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Always compile with &lt;code&gt;-g&lt;/code&gt;, then strip separately for release.
&lt;/li&gt;
&lt;li&gt;Store symbol files indexed by Build ID in a central, backed‑up location.
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;-fno-omit-frame-pointer&lt;/code&gt; for more reliable backtraces.
&lt;/li&gt;
&lt;li&gt;Test core dump generation in a staging environment that mirrors production.
&lt;/li&gt;
&lt;li&gt;Automate core collection and symbol archiving as part of your deployment pipeline.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This workflow covers every crash scenario — from “no core file” to “no symbols” to “full debug context.”&lt;br&gt;&lt;br&gt;
Bookmark it, share it with your team, and use it as your standard operating procedure for production crash analysis.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://www.linkedin.com/feed/update/urn:li:share:7458498483239596032/" rel="noopener noreferrer"&gt;LinkedIn discussion&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>cordump</category>
      <category>legacy</category>
      <category>linux</category>
    </item>
    <item>
      <title>Beyond New and Delete: Engineering Approach with gsl::owner, std::span and clang-tidy</title>
      <dc:creator>Wang - C++ Developer</dc:creator>
      <pubDate>Sun, 26 Apr 2026 15:27:41 +0000</pubDate>
      <link>https://dev.to/legacycpp/beyond-new-and-delete-engineering-approach-with-gslowner-stdspan-and-clang-tidy-27ob</link>
      <guid>https://dev.to/legacycpp/beyond-new-and-delete-engineering-approach-with-gslowner-stdspan-and-clang-tidy-27ob</guid>
      <description>&lt;p&gt;In my previous articles, &lt;a href="https://dev.to/legacycpp/beyond-new-and-delete-a-practical-guide-to-refactoring-raw-pointers-to-smart-pointers-3pcd"&gt;Beyond new and delete: A Practical Guide to Refactoring Raw Pointers to Smart Pointers&lt;/a&gt; and &lt;a href="https://dev.to/legacycpp/beyond-new-and-delete-to-weak-pointer-10l6"&gt;Beyond new and delete: to Weak Pointer&lt;/a&gt;, I explained how to refactor raw pointers into &lt;code&gt;unique_ptr&lt;/code&gt;, &lt;code&gt;shared_ptr&lt;/code&gt;, &lt;code&gt;weak_ptr&lt;/code&gt;, and references.&lt;/p&gt;

&lt;p&gt;But swapping pointer types is only half the battle. A successful refactoring also requires a &lt;strong&gt;systematic engineering process&lt;/strong&gt; — one that combines ownership analysis, modern C++ types, static analysis, and incremental testing to ensure safety and correctness.&lt;/p&gt;

&lt;p&gt;In this article, we focus on that engineering workflow:&lt;br&gt;
&lt;strong&gt;Audit &amp;amp; Annotate&lt;/strong&gt; → &lt;strong&gt;Static Analysis&lt;/strong&gt; → &lt;strong&gt;Replace&lt;/strong&gt; → &lt;strong&gt;Refactor Incrementally&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Audit &amp;amp; Annotate&lt;/strong&gt; – Mark owning vs observer pointers, use GSL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Static Analysis&lt;/strong&gt; – Enable &lt;code&gt;-Wall&lt;/code&gt;, run clang-tidy, add sanitizers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Replace with Modern Types&lt;/strong&gt; – &lt;code&gt;unique_ptr&lt;/code&gt;, &lt;code&gt;shared_ptr&lt;/code&gt;, &lt;code&gt;span&lt;/code&gt;, references&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Refactor Incrementally&lt;/strong&gt; – Start with leaf modules, remove manual &lt;code&gt;delete&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Step 1. Audit and Annotate Ownership
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt; Make ownership explicit before changing any code.&lt;/p&gt;

&lt;p&gt;Use comments or annotations to mark which pointers own memory and which do not.&lt;br&gt;&lt;br&gt;
Consider using the &lt;strong&gt;Guidelines Support Library (GSL)&lt;/strong&gt; – available via vcpkg, Conan, or as a header‑only library (&lt;code&gt;#include &amp;lt;gsl/gsl&amp;gt;&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gsl::owner&amp;lt;T*&amp;gt;&lt;/code&gt; for owning pointers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;T*&lt;/code&gt; or &lt;code&gt;gsl::not_null&amp;lt;T*&amp;gt;&lt;/code&gt; for non-owning pointers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;gsl/gsl&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gsl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;not_null&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ptr is guaranteed non-null - no need to check!&lt;/span&gt;
    &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;legacy_owner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gsl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;owned&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This raw pointer OWNS the memory&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;owned&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2. Use Static Analysis and Compiler Options
&lt;/h2&gt;

&lt;p&gt;Enable compiler warnings for unsafe pointer usage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GCC/Clang: &lt;code&gt;-Wall -Wextra -Werror&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MSVC: &lt;code&gt;/W4&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;or Use static analysis tools to catch raw pointer misuse:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;clang-tidy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cppcheck&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run clang-tidy with Core Guidelines checks&lt;/span&gt;
clang-tidy &lt;span class="nt"&gt;--checks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'cppcoreguidelines-owning-memory,modernize-*'&lt;/span&gt; file.cpp 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other useful tools: LeakSanitizer, Valgrind, Dr. Memory.&lt;/p&gt;

&lt;p&gt;Typical warnings are listed below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Warning 1: Missing 'gsl::owner' on allocated pointer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;  &lt;span class="c1"&gt;// warning here&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning: initializing non-owner 'int *' with a newly created 'gsl::owner&amp;lt;&amp;gt;' [cppcoreguidelines-owning-memory]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: &lt;code&gt;gsl::owner&amp;lt;int*&amp;gt; data = new int[100];&lt;/code&gt; or use &lt;code&gt;std::unique_ptr&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Warning 2: Deleting a non-owner pointer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// missing owner annotation&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;// warning here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning: deleting a pointer through a type that is not marked 'gsl::owner&amp;lt;&amp;gt;' [cppcoreguidelines-owning-memory]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Mark with &lt;code&gt;gsl::owner&lt;/code&gt; or use smart pointer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Warning 3: Returning raw pointer from factory (ownership unclear)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;make_int&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;        &lt;span class="c1"&gt;// warning: returning raw pointer&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning: function returns a raw pointer that may be an owner [cppcoreguidelines-owning-memory]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: &lt;code&gt;std::unique_ptr&amp;lt;int&amp;gt; make_int()&lt;/code&gt; or mark as &lt;code&gt;gsl::owner&amp;lt;int*&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Warning 4: Assignment loses ownership
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;gsl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// warning: owner assigned to non-owner&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning: initializing non-owner 'int *' with a newly created 'gsl::owner&amp;lt;&amp;gt;' [cppcoreguidelines-owning-memory]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: &lt;code&gt;gsl::owner&amp;lt;int*&amp;gt; p = create()&lt;/code&gt;; or use &lt;code&gt;auto p = create();&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Warning 5: Using std::unique_ptr with raw delete
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;          &lt;span class="c1"&gt;// warning: manual delete on smart pointer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;warning: 'delete' applied to pointer that is owned by a smart pointer [cppcoreguidelines-owning-memory]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Remove manual &lt;code&gt;delete&lt;/code&gt; – the smart pointer handles it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. Replace with Modern Types
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ownership/Usage&lt;/th&gt;
&lt;th&gt;Modern C++ Type&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sole ownership&lt;/td&gt;
&lt;td&gt;&lt;code&gt;std::unique_ptr&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;std::make_unique&amp;lt;T&amp;gt;()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared ownership&lt;/td&gt;
&lt;td&gt;&lt;code&gt;std::shared_ptr&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;std::make_shared&amp;lt;T&amp;gt;()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-owning, never null&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;T&amp;amp;&lt;/code&gt; or &lt;code&gt;gsl::not_null&amp;lt;T*&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Prefer references when possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-owning, may be null&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;T*&lt;/code&gt; (with optional GSL annotation)&lt;/td&gt;
&lt;td&gt;Raw pointer is fine as an observer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Array/view, non-owning&lt;/td&gt;
&lt;td&gt;&lt;code&gt;std::span&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C++20 (or GSL span for older standards)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Non-owning view over array/vector&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 For dynamic arrays, consider &lt;code&gt;std::vector&amp;lt;T&amp;gt;&lt;/code&gt; over &lt;code&gt;std::unique_ptr&amp;lt;T[]&amp;gt;&lt;/code&gt; unless you need a specific allocator or C API compatibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4. Refactor Incrementally
&lt;/h2&gt;

&lt;p&gt;Start with leaf modules (fewest dependencies).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;gsl::owner&amp;lt;T*&amp;gt;&lt;/code&gt; with &lt;code&gt;std::unique_ptr&amp;lt;T&amp;gt;&lt;/code&gt; or &lt;code&gt;std::shared_ptr&amp;lt;T&amp;gt;&lt;/code&gt; as appropriate.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;std::span&amp;lt;T&amp;gt;&lt;/code&gt; for functions that take raw array pointers and sizes.&lt;/li&gt;
&lt;li&gt;Update function signatures and member variables.&lt;/li&gt;
&lt;li&gt;Remove manual &lt;code&gt;delete&lt;/code&gt; calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  An Example: Step‑by‑Step Refactoring
&lt;/h2&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;               &lt;span class="c1"&gt;// arr is not owned&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gsl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;         &lt;span class="c1"&gt;// obj is owned&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;caller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;mc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;mc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;memory&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                &lt;span class="c1"&gt;// Non-owning view&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// Ownership transferred&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;caller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// No delete needed&lt;/span&gt;

    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;mc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mc&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// No delete needed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When NOT to Refactor
&lt;/h2&gt;

&lt;p&gt;Refactoring raw pointers isn't always the right move. Consider postponing or skipping when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance‑critical hot paths – the (small) overhead of smart pointers might matter (measure first).&lt;/li&gt;
&lt;li&gt;Codebases frozen for certification – aviation, medical, or safety‑critical systems.&lt;/li&gt;
&lt;li&gt;Interfacing with C libraries – raw pointers are often unavoidable there.&lt;/li&gt;
&lt;li&gt;The code is about to be deprecated – don't invest time in dead code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reference: clang-tidy Commands for Raw Pointer Refactoring
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Check Commands (Analyze Only)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --checks='cppcoreguidelines-owning-memory' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Detect missing &lt;code&gt;gsl::owner&lt;/code&gt; annotations and improper deletions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --checks='modernize-make-unique' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find raw &lt;code&gt;new&lt;/code&gt; that can be replaced with &lt;code&gt;std::make_unique&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --checks='modernize-make-shared' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find raw &lt;code&gt;new&lt;/code&gt; that can be replaced with &lt;code&gt;std::make_shared&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --checks='modernize-use-auto' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find verbose type names that can be replaced with &lt;code&gt;auto&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --checks='modernize-use-nullptr' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find &lt;code&gt;NULL&lt;/code&gt; or &lt;code&gt;0&lt;/code&gt; that can be replaced with &lt;code&gt;nullptr&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --checks='cppcoreguidelines-owning-memory,modernize-*' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run all relevant checks together&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Fix Commands (Apply Changes)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --fix --checks='modernize-make-unique' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatically replace &lt;code&gt;new&lt;/code&gt; with &lt;code&gt;std::make_unique&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --fix --checks='modernize-make-shared' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatically replace &lt;code&gt;new&lt;/code&gt; with &lt;code&gt;std::make_shared&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --fix --checks='modernize-use-auto' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatically replace verbose types with &lt;code&gt;auto&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --fix --checks='modernize-use-nullptr' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automatically replace &lt;code&gt;NULL&lt;/code&gt; with &lt;code&gt;nullptr&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clang-tidy --fix --checks='cppcoreguidelines-owning-memory' file.cpp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;gsl::owner&lt;/code&gt; annotations (manual review still recommended)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Recommended Workflow with clang-tidy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Step 1: Run checks to see what needs fixing&lt;/span&gt;
clang-tidy &lt;span class="nt"&gt;--checks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'cppcoreguidelines-owning-memory,modernize-*'&lt;/span&gt; file.cpp

&lt;span class="c"&gt;# Step 2: Apply automatic fixes safely&lt;/span&gt;
clang-tidy &lt;span class="nt"&gt;--fix&lt;/span&gt; &lt;span class="nt"&gt;--checks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'modernize-make-unique,modernize-make-shared,modernize-use-auto,modernize-use-nullptr'&lt;/span&gt; file.cpp

&lt;span class="c"&gt;# Step 3: Re-run checks to verify fixes&lt;/span&gt;
clang-tidy &lt;span class="nt"&gt;--checks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'cppcoreguidelines-owning-memory'&lt;/span&gt; file.cpp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A professional refactoring from raw pointers to modern C++ involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicitly annotating ownership (with GSL or comments)&lt;/li&gt;
&lt;li&gt;Using compiler warnings and static analysis&lt;/li&gt;
&lt;li&gt;Replacing with the right smart pointer or view type (&lt;code&gt;unique_ptr&lt;/code&gt;, &lt;code&gt;shared_ptr&lt;/code&gt;, &lt;code&gt;std::span&lt;/code&gt;, references)&lt;/li&gt;
&lt;li&gt;Testing and reviewing at every step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach produces safer, more maintainable, and truly modern C++ code – without the sleepless nights hunting for memory leaks.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>legacy</category>
      <category>refactor</category>
      <category>clangtidy</category>
    </item>
    <item>
      <title>Beyond new and delete: to Weak Pointer</title>
      <dc:creator>Wang - C++ Developer</dc:creator>
      <pubDate>Mon, 20 Apr 2026 09:15:11 +0000</pubDate>
      <link>https://dev.to/legacycpp/beyond-new-and-delete-to-weak-pointer-10l6</link>
      <guid>https://dev.to/legacycpp/beyond-new-and-delete-to-weak-pointer-10l6</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/legacycpp/beyond-new-and-delete-a-practical-guide-to-refactoring-raw-pointers-to-smart-pointers-3pcd"&gt;previous article&lt;/a&gt;, we left one case untouched: the transition from raw pointers to weak_ptr. That's exactly what we'll dive into today.&lt;/p&gt;

&lt;p&gt;Use shared_ptr when multiple parts of your system need to keep an object alive, and you can't predict which part will outlive the others. But shared_ptr has a fatal flaw: cyclic references.&lt;/p&gt;

&lt;p&gt;When two shared_ptrs point to each other, neither can die. They hold each other hostage forever. The result? A memory leak that never gets cleaned up.&lt;/p&gt;

&lt;p&gt;Let me break it down step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Problem: What happens when objects point to each other?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Normal case (no cycle)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mother&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Owning reference&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// alice's reference count = 1&lt;/span&gt;
&lt;span class="c1"&gt;// bob's reference count = 1&lt;/span&gt;
&lt;span class="c1"&gt;// When they go out of scope, both are destroyed ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The cyclic problem
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mother&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// alice ref count = 1&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// bob ref count = 1&lt;/span&gt;

&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;father&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// bob's ref count becomes 2&lt;/span&gt;
&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mother&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// alice's ref count becomes 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Now what happens when &lt;code&gt;alice&lt;/code&gt; and &lt;code&gt;bob&lt;/code&gt; go out of scope?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;alice&lt;/code&gt; (the variable) is destroyed → alice's ref count drops from 2 → 1&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bob&lt;/code&gt; (the variable) is destroyed → bob's ref count drops from 2 → 1&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Both objects still have ref count = 1!&lt;/strong&gt; They point to each other, so neither can be destroyed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MEMORY LEAK&lt;/strong&gt; 💥&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Solution: &lt;code&gt;weak_ptr&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;weak_ptr&lt;/code&gt; is like a "peek" at the object — it doesn't increase the reference count.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mother&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Owning (increases count)&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// Observing (doesn't increase count)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// alice count = 1&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// bob count = 1&lt;/span&gt;

&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;father&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// bob's count stays 1 (weak_ptr doesn't affect it)&lt;/span&gt;
&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mother&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// alice's count becomes 2&lt;/span&gt;

&lt;span class="c1"&gt;// When variables go out of scope:&lt;/span&gt;
&lt;span class="c1"&gt;// bob count: 1 → 0 (destroyed)&lt;/span&gt;
&lt;span class="c1"&gt;// alice count: 2 → 1 → 0 (destroyed when bob's weak_ptr expires)&lt;/span&gt;
&lt;span class="c1"&gt;// NO LEAK! ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using &lt;code&gt;weak_ptr&lt;/code&gt;: The &lt;code&gt;.lock()&lt;/code&gt; method
&lt;/h2&gt;

&lt;p&gt;You can't use a &lt;code&gt;weak_ptr&lt;/code&gt; directly — you must first "lock" it to get a temporary &lt;code&gt;shared_ptr&lt;/code&gt;. .lock() atomically checks existence and acquires a shared_ptr in one thread-safe operation — there is no other safe way to access a weak_ptr's target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD: Can't use weak_ptr directly&lt;/span&gt;
&lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Compiler error!&lt;/span&gt;

&lt;span class="c1"&gt;// GOOD: Lock it first&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;// Try to get shared_ptr&lt;/span&gt;
    &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;           &lt;span class="c1"&gt;// Use it safely&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The object has been destroyed&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Father is gone&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Parent-child relationships
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Owning&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                   &lt;span class="c1"&gt;// Observing (back-pointer)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Event observers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ClickObserver&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;observers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Non-owning&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;weakObs&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;observers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;obs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weakObs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;obs&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Clean up dead observers&lt;/span&gt;
        &lt;span class="n"&gt;observers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remove_if&lt;/span&gt;&lt;span class="p"&gt;(...));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Caches
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImageCache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Still in use, return it&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Not in cache or expired, load new image&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Store as weak_ptr&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The &lt;code&gt;shared_ptr.get()&lt;/code&gt; -&amp;gt; weak_ptr
&lt;/h2&gt;

&lt;p&gt;The comment about &lt;code&gt;.get()&lt;/code&gt; means: If you ever write this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BAD pattern&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Storing raw pointer&lt;/span&gt;
&lt;span class="c1"&gt;// Later: use raw somewhere else — DANGEROUS!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's usually a sign you should use &lt;code&gt;weak_ptr&lt;/code&gt; instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GOOD pattern&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Non-owning reference&lt;/span&gt;
&lt;span class="c1"&gt;// Later: wp.lock() to safely access&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;shared_ptr&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;weak_ptr&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Owns the object&lt;/td&gt;
&lt;td&gt;Observes the object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Increases ref count&lt;/td&gt;
&lt;td&gt;Doesn't affect ref count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keeps object alive&lt;/td&gt;
&lt;td&gt;Object can die&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Always valid (until destroyed)&lt;/td&gt;
&lt;td&gt;May be expired&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Direct access with &lt;code&gt;-&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Must call &lt;code&gt;.lock()&lt;/code&gt; first&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;When to use &lt;code&gt;weak_ptr&lt;/code&gt;:&lt;/strong&gt; Any time you need a reference to an object but don't want to be responsible for keeping it alive — especially parent back-pointers, observers, and caches.&lt;/p&gt;

&lt;p&gt;Does this make the cyclic reference problem clearer?&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>legacy</category>
      <category>refactoring</category>
      <category>ptr</category>
    </item>
    <item>
      <title>Beyond new and delete: A Practical Guide to Refactoring Raw Pointers to Smart Pointers</title>
      <dc:creator>Wang - C++ Developer</dc:creator>
      <pubDate>Fri, 17 Apr 2026 05:45:18 +0000</pubDate>
      <link>https://dev.to/legacycpp/beyond-new-and-delete-a-practical-guide-to-refactoring-raw-pointers-to-smart-pointers-3pcd</link>
      <guid>https://dev.to/legacycpp/beyond-new-and-delete-a-practical-guide-to-refactoring-raw-pointers-to-smart-pointers-3pcd</guid>
      <description>&lt;p&gt;You've been there. You inherit a codebase filled with &lt;code&gt;Widget* w = new Widget()&lt;/code&gt;, manual &lt;code&gt;delete&lt;/code&gt; calls scattered across error-prone destructors, and the occasional use-after-free that crashes in production once a week.&lt;/p&gt;

&lt;p&gt;You know C++11's smart pointers are the answer. But refactoring a raw pointer to &lt;code&gt;std::unique_ptr&lt;/code&gt;, &lt;code&gt;std::shared_ptr&lt;/code&gt;, or even back to a plain reference isn't always obvious. The core question is: &lt;strong&gt;Who owns this object?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this article, we'll build a decision framework. In 15 minutes, you'll learn how to mechanically refactor raw pointers and when to choose each smart pointer—or avoid them altogether.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Decision Workflow (15-Second Check)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Raw Pointer?
    │
    ├─ Does it OWN the object?
    │       │
    │       ├─ NO  → raw reference (&amp;amp;) or raw pointer (*)
    │       │        (never delete)
    │       │
    │       └─ YES → Is ownership EXCLUSIVE?
    │                   │
    │                   ├─ YES → std::unique_ptr ← 80% of cases
    │                   │
    │                   └─ NO  → Is ownership SHARED?
    │                               │
    │                               ├─ YES → Is there a CYCLE?
    │                               │           │
    │                               │           ├─ YES → std::weak_ptr
    │                               │           │
    │                               │           └─ NO  → std::shared_ptr
    │                               │
    │                               └─ NO  → Re-examine design
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The 3-Question Drill:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer → Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Owns?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No → Raw reference/pointer (never delete)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Exclusive?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes → &lt;code&gt;unique_ptr&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shared?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes → &lt;code&gt;shared_ptr&lt;/code&gt; (check for cycles → &lt;code&gt;weak_ptr&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;That's it.&lt;/strong&gt; 80% of raw pointers become &lt;code&gt;unique_ptr&lt;/code&gt;. 15% become raw references. 5% become &lt;code&gt;shared_ptr&lt;/code&gt;/&lt;code&gt;weak_ptr&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Golden Rule of Refactoring
&lt;/h2&gt;

&lt;p&gt;Never change behavior while refactoring. Start with a single raw pointer. Ask three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is this pointer nullable? (Can it be &lt;code&gt;nullptr&lt;/code&gt;?)&lt;/li&gt;
&lt;li&gt;Who is responsible for deleting the object?&lt;/li&gt;
&lt;li&gt;Is ownership shared or unique?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you answer those, the path becomes clear.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Obvious Case — Exclusive Ownership → &lt;code&gt;std::unique_ptr&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;unique_ptr&lt;/code&gt; when exactly one part of the code owns the object, but the pointer might be moved or transferred.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signs you need &lt;code&gt;unique_ptr&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The raw pointer is deleted in the same class that creates it.&lt;/li&gt;
&lt;li&gt;The pointer is never copied (only moved or passed as a raw pointer to functions that don't store it).&lt;/li&gt;
&lt;li&gt;You see &lt;code&gt;delete ptr;&lt;/code&gt; in a destructor and nowhere else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Before refactoring:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;socket_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;socket_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Manual move/copy? Omitted for brevity — disaster waiting.&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;Socket&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;socket_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After refactoring:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;socket_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Socket&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="c1"&gt;// Destructor auto-deletes. Move is automatic.&lt;/span&gt;
    &lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Socket&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;socket_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key nuance:&lt;/strong&gt; You can still pass a raw pointer to a function that doesn't own the object (e.g., &lt;code&gt;void send(Socket* s)&lt;/code&gt;). Use &lt;code&gt;.get()&lt;/code&gt; for that. But never &lt;code&gt;.release()&lt;/code&gt; unless you truly mean to transfer ownership.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Heuristic:&lt;/strong&gt; If you would have used &lt;code&gt;std::auto_ptr&lt;/code&gt; (RIP), use &lt;code&gt;unique_ptr&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Shared Ownership → &lt;code&gt;std::shared_ptr&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;shared_ptr&lt;/code&gt; when multiple parts of the system need to keep the object alive and you cannot predict which one will outlive the others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signs you need &lt;code&gt;shared_ptr&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The pointer is stored in several containers or callbacks.&lt;/li&gt;
&lt;li&gt;You have &lt;code&gt;std::vector&lt;/code&gt; and multiple threads or components delete items unpredictably.&lt;/li&gt;
&lt;li&gt;You find yourself implementing reference counting manually (e.g., &lt;code&gt;AddRef&lt;/code&gt;/&lt;code&gt;Release&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Before refactoring:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This leaks if a child is referenced from two parents. Don't do this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After refactoring:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;enable_shared_from_this&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// No manual destructor.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The cost:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;shared_ptr&lt;/code&gt; doubles the size (two pointers: object + control block) and uses atomic increments (slower, but fine for most apps). Only reach for &lt;code&gt;shared_ptr&lt;/code&gt; when &lt;code&gt;unique_ptr&lt;/code&gt; is impossible.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Observer Case — Breaking Cycles → &lt;code&gt;std::weak_ptr&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;shared_ptr&lt;/code&gt; has a fatal flaw: &lt;strong&gt;cyclic references&lt;/strong&gt;. If two &lt;code&gt;shared_ptr&lt;/code&gt;s point to each other, they never die.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mother&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Cycle!&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shared_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mother&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Owning&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;weak_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;father&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// Observing (no cycle)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;weak_ptr&lt;/code&gt; when you need a non-owning reference to an object managed by &lt;code&gt;shared_ptr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Full explanation and refactoring techniques for &lt;code&gt;weak_ptr&lt;/code&gt; → &lt;a href="https://dev.to/legacycpp/beyond-new-and-delete-to-weak-pointer-10l6"&gt;see  the next article&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The No-Ownership Case — Raw References &amp;amp; Raw Pointers
&lt;/h2&gt;

&lt;p&gt;Smart pointers express ownership. Not every pointer needs to be smart. In fact, using a &lt;code&gt;shared_ptr&lt;/code&gt; for every single pointer is an anti-pattern (slow, bloated, semantically wrong).&lt;/p&gt;

&lt;p&gt;Use plain references (&lt;code&gt;&amp;amp;&lt;/code&gt;) or raw pointers (&lt;code&gt;*&lt;/code&gt;) for non-owning observers when you are certain the lifetime is longer than the use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use a raw reference:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The object must exist (no &lt;code&gt;nullptr&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;You are not storing it for later (e.g., function parameter).&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;void draw(const Shape&amp;amp; shape);&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to use a raw pointer:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The observer can be null.&lt;/li&gt;
&lt;li&gt;You need to reseat it (references can't be reassigned).&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;void setLogger(Logger* logger) { logger_ = logger; }&lt;/code&gt; – but only if the &lt;code&gt;Logger&lt;/code&gt; outlives this object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The critical rule:&lt;/strong&gt;&lt;br&gt;
A raw pointer or reference must never be deleted. If you see &lt;code&gt;delete ptr&lt;/code&gt; on a raw pointer, you made a wrong turn.&lt;/p&gt;


&lt;h2&gt;
  
  
  Real Refactoring Example — A Cache System
&lt;/h2&gt;

&lt;p&gt;Let's refactor a small in-memory cache from raw pointers to smart pointers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before (broken):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unordered_map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="c1"&gt;// Usage: who deletes the Data? Cache does, but what if two caches share it?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (clear ownership):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cache&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Cache owns the Data exclusively.&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unordered_map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Returns non-owning observer&lt;/span&gt;
    &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now ownership is explicit. The cache destroys the data. Callers can observe but not delete.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Pitfalls During Refactoring
&lt;/h2&gt;

&lt;p&gt;❌ &lt;strong&gt;Mixing ownership styles&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;std::shared_ptr&amp;lt;Widget&amp;gt; sp = std::make_unique&amp;lt;Widget&amp;gt;();&lt;/code&gt; // Works but confusing. Prefer consistent smart pointer types.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Using &lt;code&gt;shared_ptr&lt;/code&gt; for everything "just to be safe"&lt;/strong&gt;&lt;br&gt;
This hides design issues and kills performance (atomic ops). Refactor to &lt;code&gt;unique_ptr&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Calling &lt;code&gt;.get()&lt;/code&gt; and storing the raw pointer long-term&lt;/strong&gt;&lt;br&gt;
That's just raw pointer ownership again. Store the smart pointer or use &lt;code&gt;weak_ptr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;❌ &lt;strong&gt;Forgetting &lt;code&gt;make_unique&lt;/code&gt; / &lt;code&gt;make_shared&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Old: std::unique_ptr&amp;lt;Widget&amp;gt; p(new Widget());&lt;/span&gt;
&lt;span class="c1"&gt;// New:&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;make_unique&lt;/code&gt; is exception-safe and slightly more efficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Not to Refactor
&lt;/h2&gt;

&lt;p&gt;Some raw pointers are fine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-owning iterators into a buffer.&lt;/li&gt;
&lt;li&gt;Polymorphic casts in performance-critical loops (you still need to ensure lifetime).&lt;/li&gt;
&lt;li&gt;Legacy APIs that expect raw pointers and manage their own memory. Don't force &lt;code&gt;shared_ptr&lt;/code&gt; into a C-style callback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In those cases, &lt;strong&gt;document the lifetime contract&lt;/strong&gt;: "This pointer is valid only during the call."&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Ownership Is Documentation
&lt;/h2&gt;

&lt;p&gt;Refactoring raw pointers to smart pointers isn't just about memory safety—it's about expressing intent. When I see &lt;code&gt;unique_ptr&lt;/code&gt;, I know: This object has a single, clear owner. When I see &lt;code&gt;shared_ptr&lt;/code&gt;, I know: Multiple agents collaborate here. When I see a raw reference, I know: I'm just visiting; don't delete.&lt;/p&gt;

&lt;p&gt;Next time you look at a &lt;code&gt;MyClass*&lt;/code&gt; member variable, ask: &lt;strong&gt;"Who owns this?"&lt;/strong&gt; Then pick the tool that answers that question in code.&lt;/p&gt;

&lt;p&gt;Your future self—and your teammates—will thank you.&lt;/p&gt;




</description>
      <category>cpp</category>
      <category>leagcy</category>
      <category>refactoring</category>
      <category>ptr</category>
    </item>
  </channel>
</rss>
