Effective C++ 條款27: 盡量用const、enum、inline替換 #define

Effective C++ 條款27:盡量用const、enum、inline替換#define


核心思想使用編譯器(const, enum, inline)替代預處理器(#define),讓編譯器進行語義檢查,避免宏替換引發的錯誤和調試困難,提升代碼健壯性和可維護性。

?? 1. 宏定義常量的弊端

問題點

  • 宏定義在預處理階段被簡單替換,不進入符號表,導致調試困難
  • 宏沒有作用域限制,容易造成命名沖突
  • 宏替換可能導致代碼膨脹

錯誤示例

#define PI 3.14159             // 宏常量
#define MAX(a,b) ((a) > (b) ? (a) : (b))  // 宏函數

缺點分析

  1. 編譯錯誤信息顯示3.14159而非PI,難以定位問題
  2. MAX(++a, b)可能導致++a執行兩次
  3. 無法創建類作用域的常量
  4. 宏函數缺乏類型安全檢查

解決方案:使用const常量

const double Pi = 3.14159;     // 類型安全常量
constexpr double ModernPi = 3.14159;  // C++11編譯期常量

類內常量:使用static const成員

class Circle {
private:static const double Pi;    // 類內聲明// 或使用C++17內聯靜態成員static inline const double ModernPi = 3.14159; 
};
const double Circle::Pi = 3.14159;  // 類外定義

🚨 2. 枚舉技巧(enum hack)

適用場景

  • 需要類內常量且避免靜態成員地址被獲取
  • 編譯器不允許靜態整型常量在類內初始化(舊編譯器)
  • 模板元編程基礎技術

示例

class GamePlayer {
private:enum { NumTurns = 5 };     // 枚舉常量int scores[NumTurns];      // 使用枚舉常量
};

優點

  1. 行為類似#define(不能取地址)
  2. 避免宏的缺點,提供作用域限制
  3. 編譯期確定值,可用于數組大小

?? 3. 用inline函數替換宏函數

宏函數的致命缺陷

#define SQUARE(x) ((x) * (x))
int result = SQUARE(a++);  // 展開為((a++) * (a++)) → 未定義行為

解決方案:使用內聯函數模板

template<typename T>
inline T square(const T& x) { return x * x; 
}// C++20概念約束
template<std::integral T>
inline auto square(const T& x) { return x * x; 
}

優點

  1. 參數只求值一次
  2. 支持類型檢查和重載
  3. 遵守作用域規則
  4. 可調試性

📊 4. 關鍵原則與替換策略
宏使用場景替換方案優勢
全局常量const常量或constexpr類型安全、可調試、作用域控制
類內整型常量static const或enum避免宏污染、支持封裝
類內非整型常量static const(外定義)類型安全、作用域控制
函數宏inline函數(或函數模板)避免多次求值、類型安全
編譯期常量表達式constexpr(C++11)編譯期計算、類型安全

現代C++擴展

// constexpr常量函數
constexpr int factorial(int n) {return (n <= 1) ? 1 : n * factorial(n-1);
}// C++20 consteval (立即函數)
consteval int compileTimeSquare(int n) {return n * n;
}

💡 關鍵原則總結

  1. 常量用const或constexpr
    • 全局常量用const/constexpr定義
    • 類內常量用static const(expr)或enum
  2. 函數宏用inline函數
    • 使用內聯函數模板替代帶參數的宏
    • 支持類型推導和重載
  3. 枚舉技巧備用
    • 當需要禁止取地址或舊編譯器不支持時使用
    • 模板元編程中常用
  4. 避免宏污染
    • 宏無作用域,用命名空間管理常量
    • 使用編譯器可見實體替代預處理器符號

錯誤模式重現

#define ARRAY_SIZE 100
#define MAX(a,b) ((a) > (b) ? (a) : (b))class DataProcessor {
public:int buffer[ARRAY_SIZE];  // 宏常量void process(int x, int y) {int m = MAX(x++, y);  // 危險宏}
};// 鏈接問題:非整型類內常量
class Config {static const double Factor; // 需要類外定義
};

安全重構方案

constexpr int ArraySize = 100;  // 編譯期常量template<typename T>
inline T max(const T& a, const T& b) { return a > b ? a : b; 
}class DataProcessor {
public:int buffer[ArraySize];  // 安全常量void process(int x, int y) {int m = max(x, y);  // 安全函數x++;}
};// 類內常量解決方案
class Config {
public:// 方案1:使用枚舉enum { FactorTimes100 = 175 }; // 整型常量// 方案2:C++17內聯靜態成員static inline const double Factor = 1.75; // 方案3:外部定義(C++11前)static const double LegacyFactor; 
};
const double Config::LegacyFactor = 1.75;// 編譯期計算
constexpr auto computedValue = factorial(5);

ctor = 1.75;

// 方案3:外部定義(C++11前)
static const double LegacyFactor; 

};
const double Config::LegacyFactor = 1.75;

// 編譯期計算
constexpr auto computedValue = factorial(5);

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/918000.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/918000.shtml
英文地址,請注明出處:http://en.pswp.cn/news/918000.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

芯谷科技--高效噪聲降低解決方案壓縮擴展器D5015

在無繩電話系統中&#xff0c;噪聲降低是提升通話質量的關鍵。 D5015 壓縮擴展器&#xff0c;通過集成壓縮器和擴展器&#xff0c;有效降低了傳輸噪聲&#xff0c;同時保持了信號的完整性。D5015 采用 SOP20 和 DIP20 封裝形式&#xff0c;具有低電壓工作、低功耗、高集成度等特…

LabVIEW車床靜剛度自動測

?基于LabVIEW 平臺開發車床靜剛度自動測試系統&#xff0c;針對傳統生產法測量中人工誤差大、計算復雜、效率低等問題&#xff0c;結合誤差復映規律與剛度方程&#xff0c;通過高精度硬件與軟件協同&#xff0c;實現試件加工前后尺寸的在線采集、自動計算與報告生成&#xff0…

汽車流通行業4S門店生存性指標:零服吸收率

我們在做汽車4S集團的商業智能BI數據分析項目中&#xff0c;對于4S店的管理&#xff0c;大家經常會提到一個分析指標&#xff0c;叫“零服吸收率”&#xff0c;這個大概是什么意思呢&#xff1f;簡單來說就是4S門店一臺車都沒有賣出的情況下&#xff0c;光靠售后服務部分的收益…

第一性原理科學計算服務器如何選擇配置-CPU選擇篇

一、 大多數人知道的 (顯性因素)核心數與線程數 (Core Count & Thread Count): 重要性&#xff1a; 核心是王道。 科學計算任務&#xff08;如仿真、建模、數據分析、機器學習訓練&#xff09;絕大多數都高度并行化&#xff0c;可以同時利用多個核心進行計算。選擇建議&…

Java 后端 + JavaScript 前端 實現按鈕級別權限控制的解決方案

Java JavaScript 前后端協同實現按鈕權限控制 在后臺管理系統中&#xff0c;不同用戶根據角色和數據狀態應展示不同的操作按鈕&#xff0c;比如編輯、刪除、審批、提交等操作。本文將介紹一種通過 Java 后端生成按鈕權限 JSON&#xff0c;前端通過 jQuery 解析控制按鈕顯示的…

RAG面試內容整理-18. 向量量化與索引壓縮技術(PQ, HNSW 等)

當知識庫規模達到百萬甚至數億級文檔時,向量索引的存儲和查詢效率成為關鍵瓶頸。向量量化是一類用較低比特表示近似向量的方法,大幅壓縮內存占用并加速相似度計算。PQ(Product Quantization)是其中最著名的方法之一,被Faiss等庫廣泛實現。PQ的思想是將高維向量劃分為多個子…

如何顯示一個 Elasticsearch 索引的字段

作者&#xff1a;來自 Elastic JD Armada 學習如何使用 _mapping 和 _search API、子字段、合成 _source 和運行時字段來顯示 Elasticsearch 索引的字段。 更多閱讀&#xff1a; Elasticsearch&#xff1a;從搜索中獲取選定的字段 fields Elasticsearch&#xff1a;inverted …

vue3父組件把一個對象整體傳入子組件,還是把一個對象的多個屬性分成多個參數傳入

以一個對象整體傳入時&#xff0c;對象的定義&#xff1a;<template><div><p>姓名: {{ userInfo.name }}</p><p>年齡: {{ userInfo.age }}</p><p>郵箱: {{ userInfo.email }}</p></div> </template> <script s…

【unitrix數間混合計算】2.1 數間混合計算模塊(src/number/mod.rs)

一、源碼 這段代碼是一個Rust模塊的聲明和導出配置&#xff0c;主要用于實現"類型級數與基本類型混合計算"的功能。 //! 類型級數與基本類型混合計算// 模塊聲明 // -------------------------------- mod types; // 結構體定義 mod normalize; …

脫機部署k3s

離線部署 K3s 文檔 1. 準備工作 操作系統準備&#xff1a;確保服務器已安裝好基礎操作系統&#xff08;Ubuntu、CentOS 等&#xff09;。關閉防火墻或放通端口&#xff1a;建議關閉防火墻或確保 6443、10250 等端口已開放。準備離線資源文件&#xff1a; 下載地址 k3s-airga…

[失敗記錄] 使用HBuilderX創建的uniapp vue3項目添加tailwindcss3的完整過程

寫在前面 放棄了。。。 1&#xff09;方案1 - 參考下面的“完整步驟” - 安裝成功&#xff0c;運行成功&#xff0c;但是&#xff01;好多class不生效&#xff01; 2&#xff09;方案2 - 不安裝tailwindcss&#xff0c;直接使用獨立的編譯好的完整css文件&#xff01; …

使用Idea去git項目,發現拉取和推送都很慢的問題

在大多數情況下&#xff0c;用Idea去對項目進行拉取和推送是很方便的&#xff0c;對于新手來說也是非常友好的但是最近博主遇到了一個問題&#xff0c;就是我feat一個簡單的類&#xff0c;去提交推送都需要很長的時間&#xff0c;甚至是20分鐘&#xff0c;博主去找了很多方法。…

無人機圖傳的得力助手:5G 便攜式多卡高清視頻融合終端的協同應用

前言在無人機作業中&#xff0c;圖傳系統是連接空中與地面的關鍵紐帶&#xff0c;而 5G 便攜式多卡高清視頻融合終端雖不直接搭載于無人機&#xff0c;卻能通過地面協同突破傳統微波圖傳的局限&#xff0c;為無人機遠程監控、應急指揮提供穩定高效的傳輸支撐。型號&#xff1a;…

【博客系統UI自動化測試報告】

博客系統UI自動化測試報告一、項目背景二、測試內容(一)測試用例(二)測試賬號(三&#xff09;使用Selenium進行Web自動化測試1.環境搭建2.創建瀏覽器驅動3.編寫博客登陸模塊的測試用例代碼4.編寫博客主頁展示模塊的測試用例代碼5.編寫博客創作模塊的測試用例代碼6.編寫博客查看…

簡單手寫Transformer:原理與代碼詳解

Transformer 作為 NLP 領域的里程碑模型&#xff0c;徹底改變了序列建模的方式。它基于自注意力機制&#xff0c;擺脫了 RNN 的序列依賴&#xff0c;實現了并行計算&#xff0c;在機器翻譯、文本生成等任務中表現卓越。本文將從零開始&#xff0c;手寫一個簡化版 Transformer&a…

Numpy科學計算與數據分析:Numpy入門之數組操作與科學計算基礎

Numpy入門實踐&#xff1a;從零開始掌握科學計算利器 學習目標 通過本課程的學習&#xff0c;學員將了解Numpy的歷史背景、核心特點及其在科學計算中的重要性。學員將掌握如何使用Numpy進行數組操作&#xff0c;包括數組的創建、索引、切片以及基本的數學運算&#xff0c;為后…

python:講懂決策樹,為理解隨機森林算法做準備,以示例帶學習,通俗易懂,容易理解和掌握

為什么要講和學習決策樹呢?主要是決策樹(包括隨機森林算法)不需要數據的預處理。現實世界的數據往往“臟亂差”,決策樹讓你在數據準備上可以少花很多功夫,快速上手,用起來非常的“省心”。總之,決策樹是機器學習領域里最直觀易懂、解釋性最強、應用最廣泛的基礎模型之一…

C語言:單鏈表學習

文件&#xff1a;main.c #include "linkedList.h"int main(int argc, char *argv[]) {// 創建頭結點NODE *head NULL;// 創建鏈表if (llist_create(&head, 666) < 0){perror("鏈表創建失敗&#xff01;");return -1;}// 向鏈表插入數據llist_addTa…

使用 decimal 包解決 go float 浮點數運算失真

文章目錄問題解決注意問題 go float 在運算的時候會出現精度問題 package mainimport ("fmt" )func main() {var a float64 0.3var b float64 0.6fmt.Println("ab", ab) // 你以為是 0.9 但是結果是&#xff1a;0.8999999999999999 }你觀察到的 0.3 …

MongoDB學習專題(六)復制集和分片集群

1、概念MongoDB復制集的主要意義在于實現服務高可用&#xff0c;類似于Redis中的哨兵模式2、功能1. 數據寫入主節點時將數據復制到另一個副本節點上2. 主節點發生故障時自動選舉出一個新的替代節點在實現高可用的同時&#xff0c;復制集實現了其他幾個作用數據分發&#xff1a;…