<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Legacy Code on kenji.blog</title><link>http://kenji.blog/zh-tw/tags/legacy-code/</link><description>Recent content in Legacy Code on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 20:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/zh-tw/tags/legacy-code/index.xml" rel="self" type="application/rss+xml"/><item><title>重構的秘訣：安全地改善舊有 C++ 程式碼</title><link>http://kenji.blog/zh-tw/p/refactoring-legacy-cpp-code-safely/</link><pubDate>Sat, 12 Sep 2026 20:00:00 +0900</pubDate><guid>http://kenji.blog/zh-tw/p/refactoring-legacy-cpp-code-safely/</guid><description>&lt;img src="http://kenji.blog/p/refactoring-legacy-cpp-code-safely/img/eyecatch.jpg" alt="Featured image of post 重構的秘訣：安全地改善舊有 C++ 程式碼" />&lt;h1 id="重構的秘訣安全地改善舊有-c-程式碼">重構的秘訣：安全地改善舊有 C++ 程式碼
&lt;/h1>&lt;p>在現代的軟體開發中，與「舊有程式碼 (Legacy Code)」的抗爭是無法避免的道路。特別是在 C++ 這個語言中，舊有程式碼的威脅是其他語言無法比擬的。手動的記憶體管理（原始指標 (raw pointers) 與 &lt;code>new&lt;/code> / &lt;code>delete&lt;/code> 的風暴）、全域變數的濫用、缺乏例外安全性，以及最重要的是「沒有測試」這個事實。Michael Feathers 在其名著《修改軟體的藝術 (Working Effectively with Legacy Code)》中斷言：「沒有測試的程式碼就是舊有程式碼」。&lt;/p>
&lt;p>本文將從理論與實踐兩方面，徹底解說如何將累積了數十年的舊有 C++ 程式碼庫，安全且確實地轉移至 Modern C++ (C++11/14/17/20) 並進行重構的秘訣。從技術債的數學模型開始，到安全的依賴關係分離，以及使用現代語言功能進行程式碼的淨化，網羅了實用的方法。&lt;/p>
&lt;hr>
&lt;h2 id="1-複雜度與技術債的數學模型">1. 複雜度與技術債的數學模型
&lt;/h2>&lt;p>為了讓重構正當化，必須將目前程式碼庫所擁有的問題予以量化。作為測量程式碼結構複雜度的指標，最常見的就是「循環複雜度 (Cyclomatic Complexity)」。這個複雜度是基於控制流程圖 (Control Flow Graph) 的圖論，以下列公式定義：&lt;/p>
$$ M = E - N + 2P $$&lt;p>在這裡，&lt;/p>
&lt;ul>
&lt;li>$M$ 是循環複雜度&lt;/li>
&lt;li>$E$ 是圖的邊（處理的流程、轉移）的數量&lt;/li>
&lt;li>$N$ 是圖的節點（處理的基本區塊）的數量&lt;/li>
&lt;li>$P$ 是連通元件的數量（通常在單一函式或方法中 $P=1$）&lt;/li>
&lt;/ul>
&lt;p>複雜度 $M$ 越大，為了網羅測試該函式所需的測試案例數量將呈線性增長，或者根據條件分支的組合，呈指數級增長。此外，有一個經驗法則，就是錯誤發生的機率 $P(bug)$，相對於複雜度 $M$ 會呈指數級增加。若將此以類似泊松分佈 (Poisson distribution) 的形式進行模型化，如下所示：&lt;/p>
$$ P(bug) = 1 - e^{-\lambda \cdot M} $$&lt;p>（這裡的 $\lambda$ 是取決於開發團隊技能或領域難度常數。）&lt;/p>
&lt;p>此外，技術債的成本會以複利的方式增加。如果將初期的技術債設為 $C_0$，每個迭代的利率（因程式碼難以修改而導致生產力下降的比例）設為 $r$，那麼 $t$ 期間後的修改成本 $Cost(t)$ 可以表示如下：&lt;/p>
$$ Cost(t) = C_0 \times (1 + r)^t $$&lt;p>這個公式明確指出了一個殘酷的事實：「放置舊有程式碼不管，將隨著時間推移導致成本呈指數級增長」。因此，債務必須及早償還（重構）。&lt;/p>
&lt;hr>
&lt;h2 id="2-重構的絕對原則測試優先-test-first">2. 重構的絕對原則：「測試優先 (Test-First)」
&lt;/h2>&lt;p>在修改舊有程式碼時，最大的恐懼在於「是否會破壞現有正常的行為（發生退化 / Regression）」。消除這種恐懼的唯一方法就是「自動化測試」。&lt;/p>
&lt;p>然而，舊有程式碼原本就沒有測試。這時最重要的就是導入「特徵化測試 (Characterization Test)」。特徵化測試不是在記錄系統「本來應該如何運作」，而是將系統「現在實際上是如何運作的」原封不動地記錄下來的測試。&lt;/p>
&lt;p>以下的流程圖顯示了安全重構的生命週期。&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;鎖定目標舊有程式碼&amp;#34;] --&amp;gt; B[&amp;#34;撰寫特徵化測試&amp;#34;]
B --&amp;gt; C[&amp;#34;確認測試全部通過&amp;#34;]
C --&amp;gt; D[&amp;#34;實施小幅度的重構&amp;#34;]
D --&amp;gt; E[&amp;#34;重新執行測試&amp;#34;]
E -- &amp;#34;失敗 (Red)&amp;#34; --&amp;gt; F[&amp;#34;還原變更 (Revert)&amp;#34;]
F --&amp;gt; D
E -- &amp;#34;成功 (Green)&amp;#34; --&amp;gt; G[&amp;#34;提交程式碼 (Commit)&amp;#34;]
G --&amp;gt; H{&amp;#34;還有下一個需要改善的地方嗎？&amp;#34;}
H -- &amp;#34;Yes&amp;#34; --&amp;gt; D
H -- &amp;#34;No&amp;#34; --&amp;gt; I[&amp;#34;重構完成&amp;#34;]
&lt;/pre>
&lt;p>透過循環這個週期，開發者可以始終在安全網上修改程式碼。如果測試失敗，重要的是不要深入追究原因，而是立即 &lt;code>Revert&lt;/code>（還原）。&lt;/p>
&lt;hr>
&lt;h2 id="3-產生可測試性的接縫-seams概念">3. 產生可測試性的「接縫 (Seams)」概念
&lt;/h2>&lt;p>當嘗試為舊有程式碼添加測試時，首先面臨的障礙是「依賴關係」。如果直接連接資料庫、網路通訊、或存取硬編碼的檔案系統等發生緊密耦合，那麼要撰寫單元測試 (Unit Test) 是不可能的。&lt;/p>
&lt;p>這時登場的是「接縫 (Seam)」這個概念。接縫是指「無需編輯程式碼本身，就能改變系統行為的地方」。在 C++ 中，主要利用以下三個接縫：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>物件接縫 (Object Seams)&lt;/strong>: 利用虛擬函式 (Virtual Functions) 的多型 (Polymorphism)。&lt;/li>
&lt;li>&lt;strong>編譯期接縫 (Compile-time Seams)&lt;/strong>: 樣板 (Templates) 或 &lt;code>#include&lt;/code> 的切換。&lt;/li>
&lt;li>&lt;strong>連結期接縫 (Link-time Seams)&lt;/strong>: 建置時連結的函式庫或物件檔的切換。&lt;/li>
&lt;/ol>
&lt;p>充分運用這些方法，將正式環境的模組替換為測試環境用的模擬 (Mock) 物件，藉此隔離依賴關係。&lt;/p>
&lt;hr>
&lt;h2 id="4-打破緊密耦合依賴注入-dependency-injection">4. 打破緊密耦合：依賴注入 (Dependency Injection)
&lt;/h2>&lt;p>依賴注入 (DI: Dependency Injection) 是一種強大的模式，用於將物件的建立責任從類別內部抽離至外部。&lt;/p>
&lt;p>首先，我們來看看舊有且緊密耦合的 C++ 類別設計。&lt;/p>
&lt;pre class="mermaid">
classDiagram
class LegacyOrderProcessor {
-DatabaseConnection* db
-FileLogger* logger
+LegacyOrderProcessor()
+processOrder(int orderId) void
}
class DatabaseConnection {
+DatabaseConnection()
+save(int orderId) void
}
class FileLogger {
+FileLogger()
+log(string msg) void
}
LegacyOrderProcessor --&amp;gt; DatabaseConnection : &amp;#34;直接建立 (使用 new)&amp;#34;
LegacyOrderProcessor --&amp;gt; FileLogger : &amp;#34;直接建立 (使用 new)&amp;#34;
&lt;/pre>
&lt;p>這個 &lt;code>LegacyOrderProcessor&lt;/code> 在建構函式內直接 &lt;code>new&lt;/code> 出 &lt;code>DatabaseConnection&lt;/code> 和 &lt;code>FileLogger&lt;/code>，因此不存在可替換成 Mock 的接縫。我們使用介面（純虛擬類別）將其重構為鬆散耦合。&lt;/p>
&lt;pre class="mermaid">
classDiagram
class IDatabase {
&amp;lt;&amp;lt;interface&amp;gt;&amp;gt;
+save(int orderId) void
}
class ILogger {
&amp;lt;&amp;lt;interface&amp;gt;&amp;gt;
+log(string msg) void
}
class ModernOrderProcessor {
-std::unique_ptr~IDatabase~ db
-std::shared_ptr~ILogger~ logger
+ModernOrderProcessor(std::unique_ptr~IDatabase~ db, std::shared_ptr~ILogger~ logger)
+processOrder(int orderId) void
}
class DatabaseConnection {
+save(int orderId) void
}
class FileLogger {
+log(string msg) void
}
IDatabase &amp;lt;|.. DatabaseConnection : &amp;#34;實作&amp;#34;
ILogger &amp;lt;|.. FileLogger : &amp;#34;實作&amp;#34;
ModernOrderProcessor --&amp;gt; IDatabase : &amp;#34;DI (建構函式注入)&amp;#34;
ModernOrderProcessor --&amp;gt; ILogger : &amp;#34;DI (建構函式注入)&amp;#34;
&lt;/pre>
&lt;h3 id="舊有程式碼範例-c03">舊有程式碼範例 (C++03)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">LegacyOrderProcessor&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DatabaseConnection&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">db_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">FileLogger&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">logger_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LegacyOrderProcessor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">DatabaseConnection&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;localhost&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3306&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger_&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">FileLogger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;/var/log/app.log&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">LegacyOrderProcessor&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">db_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">logger_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">processOrder&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">orderId&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 處理...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">db_&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">save&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orderId&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger_&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Order processed&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="重構後-modern-c">重構後 (Modern C++)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 介面定義 (物件接縫)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">class&lt;/span> &lt;span class="nc">IDatabase&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="o">~&lt;/span>&lt;span class="n">IDatabase&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">default&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">save&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">orderId&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ILogger&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="o">~&lt;/span>&lt;span class="n">ILogger&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">default&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">virtual&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">msg&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 從外部注入依賴關係的設計
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">class&lt;/span> &lt;span class="nc">ModernOrderProcessor&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">IDatabase&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">db_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">ILogger&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">logger_&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 建構函式注入 (Constructor Injection)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">ModernOrderProcessor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">IDatabase&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">ILogger&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">logger&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">:&lt;/span> &lt;span class="n">db_&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">move&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">)),&lt;/span> &lt;span class="n">logger_&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">move&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logger&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">processOrder&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">orderId&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db_&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">save&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orderId&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger_&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Order processed&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>藉由這樣修改設計，可以使用諸如 Google Mock (gmock) 等框架輕鬆建立 &lt;code>IDatabase&lt;/code> 的模擬物件，讓測試驅動開發 (TDD) 成為可能。&lt;/p>
&lt;hr>
&lt;h2 id="5-解構萬惡的全域變數與單例模式-singleton">5. 解構萬惡的全域變數與單例模式 (Singleton)
&lt;/h2>&lt;p>在舊有的 C++ 中，最令人頭痛的莫過於全域變數與「單例模式 (Singleton Pattern)」的濫用。單例模式乍看之下是個便利的設計模式，但其實際上不過是「披著物件導向外衣的全域變數」而已。&lt;/p>
&lt;p>全域狀態會導致狀態在測試案例之間共享，使得測試無法平行執行，並引發原因不明的不穩定測試 (Flaky Tests)。&lt;/p>
&lt;p>解決方案是消除對隱式全域狀態的依賴，並將必要的狀態明確地作為函式的參數傳遞（參數化）。這被稱為「傳遞上下文 (Context Passing)」。&lt;/p>
&lt;hr>
&lt;h2 id="6-記憶體管理的現代化與-raii-的精髓">6. 記憶體管理的現代化與 RAII 的精髓
&lt;/h2>&lt;p>C++98/03 時代的程式碼，&lt;code>new&lt;/code> 和 &lt;code>delete&lt;/code> 散佈在程式碼的各個角落，成為記憶體洩漏 (Memory Leak) 和懸空指標 (Dangling Pointers) 的溫床。在 Modern C++ (C++11 之後) 中，&lt;strong>所有權 (Ownership)&lt;/strong> 的概念在語言層面受到支援，使用智慧型指標 (Smart Pointers) 進行安全的資源管理成為了標準。&lt;/p>
&lt;h3 id="raii-resource-acquisition-is-initialization">RAII (Resource Acquisition Is Initialization)
&lt;/h3>&lt;p>RAII 是 C++ 中最重要的慣用語 (Idiom)。它將資源的獲取與物件的初始化（建構函式）結合，並將資源的釋放與物件的銷毀（解構函式）結合，確保在離開作用域時能確實地釋放資源。&lt;/p>
&lt;p>即使發生了例外 (Exceptions)，在堆疊展開 (Stack Unwinding) 的過程中，區域變數的解構函式也會自動被呼叫，因此可以防止資源洩漏。&lt;/p>
&lt;p>&lt;strong>Before (危險的舊有程式碼)&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">processFile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="kt">char&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">filename&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">FILE&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">file&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fopen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">filename&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;r&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Data&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">Data&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">readData&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 容易忘記
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">fclose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 容易忘記
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">process&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">(...)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 避免發生例外時的記憶體洩漏
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">fclose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fclose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>這個程式碼在控制流程的每個分支都需要手動釋放資源，是非常脆弱的結構。&lt;/p>
&lt;p>&lt;strong>After (活用 RAII 與智慧型指標)&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">processFile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">filename&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// std::ifstream 使用 RAII 管理檔案代碼 (file handle)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">ifstream&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">filename&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">is_open&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// std::unique_ptr 是使用 RAII 管理堆積 (Heap) 記憶體的獨佔擁有者
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">auto&lt;/span> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_unique&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Data&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">readData&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 在離開作用域時會自動釋放
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 即使發生例外，unique_ptr 和 ifstream 的解構函式
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 也會確保資源被釋放，因此是安全的（保證零記憶體洩漏）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">process&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>透過這次重構，程式碼量大幅減少，意圖變得明確，最重要的是完美地保證了例外安全性 (Exception Safety)。&lt;/p>
&lt;hr>
&lt;h2 id="7-透過-modern-c-功能群提升表現力">7. 透過 Modern C++ 功能群提升表現力
&lt;/h2>&lt;p>在重構舊有程式碼時，應該充分利用伴隨語言功能更新所帶來的好處。&lt;/p>
&lt;h3 id="71-使用-auto-進行型別推斷">7.1. 使用 &lt;code>auto&lt;/code> 進行型別推斷
&lt;/h3>&lt;p>將長迭代器等冗長的型別名稱替換為 &lt;code>auto&lt;/code>，可以提升可讀性。然而，最佳實踐並不是將所有東西都改成 &lt;code>auto&lt;/code>，而是限定在「只要看右邊就能清楚知道型別的情況」。&lt;/p>
&lt;h3 id="72-使用-constexpr-與-consteval-進行編譯期計算">7.2. 使用 &lt;code>constexpr&lt;/code> 與 &lt;code>consteval&lt;/code> 進行編譯期計算
&lt;/h3>&lt;p>為了減少執行期的負擔，並在編譯時偵測錯誤，積極活用 &lt;code>constexpr&lt;/code>。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 舊有程式碼（巨集或執行期計算）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#define MAX_BUFFER_SIZE 1024
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="kt">double&lt;/span> &lt;span class="n">PI&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">3.1415926535&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">double&lt;/span> &lt;span class="nf">calculateCircleArea&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">double&lt;/span> &lt;span class="n">radius&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">PI&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">radius&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">radius&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Modern C++ (C++20 之後) 的風格
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">constexpr&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">size_t&lt;/span> &lt;span class="n">MaxBufferSize&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1024&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">constexpr&lt;/span> &lt;span class="kt">double&lt;/span> &lt;span class="n">Pi&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">3.14159265358979323846&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// consteval (C++20) 保證可以在編譯期求值
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">consteval&lt;/span> &lt;span class="kt">double&lt;/span> &lt;span class="nf">calculateCircleArea&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">double&lt;/span> &lt;span class="n">radius&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Pi&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">radius&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">radius&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 執行期成本為零。編譯時計算結果的常數會直接嵌入二進制檔案中。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">constexpr&lt;/span> &lt;span class="kt">double&lt;/span> &lt;span class="n">area&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">calculateCircleArea&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">10.0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="73-nodiscard-屬性">7.3. &lt;code>[[nodiscard]]&lt;/code> 屬性
&lt;/h3>&lt;p>為了防止忽略函式回傳值（特別是錯誤碼或重要狀態）的 Bug 發生，添加 &lt;code>[[nodiscard]]&lt;/code> 屬性。這樣一來，編譯器就會針對不接收回傳值的呼叫發出警告。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="na">[[nodiscard]]&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="n">initializeSystem&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// 禁止忽略回傳值
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="8-自動化工具的活用與持續改善">8. 自動化工具的活用與持續改善
&lt;/h2>&lt;p>手動修正大規模的舊有程式碼庫是不切實際的。借助工具鏈的力量是通往成功的捷徑。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Clang-Tidy&lt;/strong>: 強大的 C++ Linter 與靜態分析工具。啟用 &lt;code>modernize-*&lt;/code> 系列的檢查，它可以自動套用 (Fix-it) 如應用 &lt;code>auto&lt;/code>、替換為 &lt;code>nullptr&lt;/code>、添加 &lt;code>override&lt;/code> 等操作。&lt;/li>
&lt;li>&lt;strong>AddressSanitizer (ASan)&lt;/strong>: 作為編譯選項 (&lt;code>-fsanitize=address&lt;/code>) 納入，可以在執行期準確地定位出記憶體洩漏與緩衝區溢位 (Buffer Overrun)。執行測試時務必啟用它。&lt;/li>
&lt;li>&lt;strong>建構 CI/CD 管線&lt;/strong>: 使用 GitHub Actions 或 GitLab CI，對所有的 Pull Request 執行建置、自動測試與靜態分析，以防止新的技術債侵入。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="9-結論">9. 結論
&lt;/h2>&lt;p>重構舊有的 C++ 程式碼，絕不是一朝一夕就能完成的。那就像是在對系統進行外科手術，是一項細膩且大膽的工作。&lt;/p>
&lt;p>請將本文中解說的以下步驟銘記在心。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>測量複雜度，基於事實制定策略&lt;/strong>&lt;/li>
&lt;li>&lt;strong>找出接縫，使用特徵化測試來保護系統&lt;/strong>&lt;/li>
&lt;li>&lt;strong>透過 DI 打破緊密耦合，根除全域狀態&lt;/strong>&lt;/li>
&lt;li>&lt;strong>透過 RAII 與智慧型指標消除對記憶體管理的擔憂&lt;/strong>&lt;/li>
&lt;li>&lt;strong>活用 Modern C++ 的功能，讓編譯器為您工作&lt;/strong>&lt;/li>
&lt;/ol>
&lt;p>抱持著「童子軍規則（離開營地時要比來的時候更乾淨）」的精神，在日常的開發任務中一點一滴地，但確實地持續改善程式碼，這才是重構真正的秘訣。&lt;/p></description></item></channel></rss>