【學習筆記】C++代碼規范整理

【學習筆記】C++代碼規范整理

一、匿名空間namespace

匿名命名空間(Anonymous Namespace)是一種特殊的命名空間聲明方式,其作用是將聲明的成員限定在當前編譯單元(源文件)內可見,類似于使用 static 關鍵字修飾全局變量 / 函數的效果。

特性匿名命名空間static 修飾全局符號
作用域當前編譯單元(源文件)當前編譯單元
鏈接屬性內部鏈接(Internal Linkage)內部鏈接
可修飾類型變量、函數、類、結構體等所有實體僅變量、函數
語法靈活性可嵌套在其他命名空間中不可嵌套
外部訪問規則在匿名命名空間所屬的源文件內,可直接調用成員函數外部通過命名空間名+“::”訪問通過中間接口封裝

外部訪問namespace內部接口:

// test.h(頭文件,聲明具名命名空間)
namespace MyNamespace {void sharedFunc(); // 聲明為具名命名空間成員
}// test.cpp(源文件,定義具名命名空間函數)
#include "test.h"
namespace MyNamespace {void sharedFunc() { // 具名命名空間,可跨文件訪問std::cout << "Shared function called.\n";}
}// other.cpp(其他源文件,包含頭文件并調用)
#include "test.h"
int main() {MyNamespace::sharedFunc(); // 合法,通過命名空間名訪問return 0;
}

訪問static關鍵字定義的接口函數:通過中間接口封裝

// file1.c
static void privateFunc() { /* ... */ } // 內部函數void callPrivateFunc() { // 公有接口privateFunc(); // 內部調用
}// file2.c
extern void callPrivateFunc(); // 聲明公有接口
int main() {callPrivateFunc(); // 通過公有接口間接調用return 0;
}

二、結構體對齊

在結構體中合理安排數據成員的布局可以有效減少內存占用。

核心原則:

? 1. 先放占用空間大的成員,再放小的成員:減少成員之間的填充字節。

? 2. 相同大小的成員分組排列:避免小成員插入大成員之間導致的零散填充。

內存對齊規則(以常見編譯器為例):

? ● 每個成員的起始地址必須是其自身大小的整數倍(如 int 占 4 字節,起始地址需是 4 的倍數)。

? ● 結構體的總大小必須是最大成員大小的整數倍。

struct BadLayout {char a;       // 1字節,起始地址對齊0,占用1字節         地址:0double b;  // 8字節,起始地址需是8的倍數 → 填充7字節,占用8字節   地址:8-15int c;          // 4字節,起始地址需是4的倍數(當前地址是16),占用4字節   地址:16-19
};
// 總大小:1(a)+7(填充)+8(b)+4(c) = 20 → 按最大成員8字節對齊,最終大小24字節
struct GoodLayout {double b;  // 8字節,起始地址對齊8,占用8字節     地址:0-7int c;          // 4字節,起始地址對齊4(當前地址8是4的倍數),占用4字節     地址:8-11char a;       // 1字節,起始地址對齊1(當前地址12),占用1字節   地址:12
};
// 總大小:8+4+1 = 13 → 按最大成員8字節對齊,最終大小16字節(節省8字節)

三、#pragma once

#pragma once 是一種預處理指令,用于確保頭文件在編譯過程中只被包含一次,從而防止因重復包含導致的編譯錯誤,如 “重復定義”(multiple definition)問題。

四、虛析構函數

一個析構函數不為virtual 的類,就是一個不愿被繼承的類。

當基類析構函數不是虛函數時,要是通過基類指針刪除派生類對象,系統只會調用基類的析構函數,而不會調用派生類的析構函數。這就可能使派生類特有的資源(像動態分配的內存、文件句柄、網絡連接等)無法被釋放,進而造成內存泄漏。

五、const

const 關鍵字用于聲明一個對象或變量是不可變的,即其值在初始化后不能被修改。

類的成員函數后面加const,表明這個函數不會對這個類對象的數據成員作任何改變。

六、盡量使用棧內存

程序運行中創建對象時主要在兩個地方,棧和堆。

在棧中創建對象(或數組)是編譯期確定的,因此開銷為零。

在堆中申請內存是運行期行為,申請、釋放都有開銷,并且存在內存碎片可能。

1.內部碎片的產生:

因為所有的內存分配必須起始于可被 4、8 或 16 整除(視處理器體系結構而定)的地址或者因為MMU的分頁機制的限制,決定內存分配算法僅能把預定大小的內存塊分配給客戶。假設當某個客戶請求一個43字節的內存塊時,因為沒有適合大小的內存,所以它可能會獲得 44字節、48字節等稍大一點的字節,因此由所需大小四舍五入而產生的多余空間就叫內部碎片。

2.外部碎片的產生:

頻繁的分配與回收物理頁面會導致大量的、連續且小的頁面塊夾雜在已分配的頁面中間,就會產生外部碎片。

假設有一塊一共有100個單位的連續空閑內存空間,范圍是099。如果你從中申請一塊內存,如10個單位,那么申請出來的內存塊就為09區間。這時候你繼續申請一塊內存,比如說5個單位大,第二塊得到的內存塊就應該為1014區間。如果你把第一塊內存塊釋放,然后再申請一塊大于10個單位的內存塊,比如說20個單位。因為剛被釋放的內存塊不能滿足新的請求,所以只能從15開始分配出20個單位的內存塊。現在整個內存空間的狀態是09空閑,1014被占用,1524被占用,2599空閑。其中09就是一個內存碎片了。如果1014一直被占用,而以后申請的空間都大于10個單位,那么09就永遠用不上了,變成外部碎片。

七、減少宏的使用

因為宏只是簡單的文本替換,缺乏類型檢查,因此不推薦使用。

除非絕對必要(如條件編譯),完全避免使用宏定義常量,統一采用 const(運行時常量)或 constexpr(編譯時常量)

// 宏方式(不推薦)
#define BUFFER_SIZE 1024
#define APP_VERSION "1.0.0.12"       //  無類型// constexpr方式(推薦)
constexpr int BUFFER_SIZE = 1024;
constexpr const char* APP_VERSION = "10.0.0.22";  // 必須加 const或者:
#include <string_view>
constexpr std::string_view APP_VERSION = "10.0.0.22";  // C++17+

所以一般正常的宏定義就可以直接用constexpr代替了。const就用作常量使用即可。

關鍵字常量性質初始化時機典型用途
const運行時常量運行時初始化值在運行時確定(如配置文件讀取)
constexpr編譯時常量編譯時初始化值必須在編譯期確定(如數組長度、模板參數

八、nullptr 代替宏NULL

C++11 之前,宏NULL 代表空指針,但是被定義為0,存在類型歧義。采用C++11 新增的關鍵字nullptr 代替NULL。

九、固定數組使用std::array 容器

C++ 11 新增了std::array 容器,用來存放固定大小的數組,訪問元素時具有越界檢查功能。

std::array<int, 5> arr = {1,2,3,4,5};
// arr[10] = 0;  // 原生數組:未定義行為(可能崩潰)
arr.at(10) = 0;  // 拋出 std::out_of_range 異常,安全捕獲錯誤

原生數組需通過 sizeof(arr)/sizeof(arr[0]) 計算長度,而 std::array 直接提供 size() 方法:

std::array<int, 5> arr;
std::cout << arr.size();  // 直接獲取,編譯期常量,安全高效

十、動態數組使用std::vector

使用std::vector 代替new[],利用new[] 動態申請內存,要用delete[] 釋放,容易發生內存泄漏。std::vector離開作用域自動釋放。并且返回的指針本身并沒有包含size 信息,訪問時不會進行越界檢查。std::vector 可以自動管理內存,并且訪問內存時可以進行邊界檢查。

std::vector<int> vec(5);
// vec[10] = 0;  // 未定義行為(可能崩潰)
vec.at(10) = 0;  // 拋出 std::out_of_range 異常,安全捕獲錯誤

十一、unordered_map 代替std::map

C++ 11 新增了unordered_map,采用hash table 的方式實現,插入和查找數據都是O(1)速度。std::map采用的好像是紅黑樹。

十二、using代替typedef

使用using 代替typedef 定義類型別名。

typedef int IntType;           // 定義類型別名
typedef void (*FuncPtr)(int);  // 定義函數指針別名using IntType = int;           // 等價于 typedef
using FuncPtr = void (*)(int); // 等價于 typedef// 模板別名(typedef 無法實現)
template<typename T>
using Vec = std::vector<T>;
// 模板別名(using 專屬)
template<typename T>
using MapString = std::map<std::string, T>;MapString<int> age_map;  // 等價于 std::map<std::string, int>// 若用 typedef 實現相同功能,需借助模板類+typedef
template<typename T>
struct MapString {typedef std::map<std::string, T> type;
};MapString<int>::type age_map;  // 語法冗余

十三、enum class代替enum

在 C++ 中,enum class(強類型枚舉) 是 C++11 引入的特性,用于替代傳統的 enum(普通枚舉)。相比普通枚舉,enum class 提供了更嚴格的類型安全和作用域控制,解決了傳統枚舉的諸多缺陷。

作用域控制(避免命名沖突)

// 普通枚舉(命名沖突)
enum Color { RED, GREEN, BLUE };
enum TrafficLight { RED, YELLOW, GREEN };  // 錯誤:重復定義 RED、GREEN// 強類型枚舉(無沖突)
enum class Color { RED, GREEN, BLUE };
enum class TrafficLight { RED, YELLOW, GREEN };Color c = Color::RED;  // 必須通過枚舉類型訪問
TrafficLight t = TrafficLight::RED;  // 無命名沖突

類型安全(禁止隱式轉換)

enum OldEnum { A, B };
enum class NewEnum { A, B };void func(int x) { /* ... */ }func(A);  // 普通枚舉:合法(隱式轉換為 int)
// func(NewEnum::A);  // 錯誤:強類型枚舉不可隱式轉換
func(static_cast<int>(NewEnum::A));  // 必須顯式轉換

顯式底層類型

// 指定底層類型為 uint8_t(節省內存)
enum class Status : uint8_t {OK = 0,ERROR = 1,PENDING = 2
};// 普通枚舉無法指定底層類型,可能浪費內存
enum OldStatus {OK,  // 通常為 int(4字節)ERROR,PENDING
};

十四、重寫明確使用override

在子類中重寫父類的虛函數時,虛函數的簽名(函數名+參數)必須與父類中的完全一樣。

如果稍有不同,就會被編譯器當作重載(overload)。

class Shape {
public:virtual double area() const = 0;
};class Circle : public Shape {
public:double area() const override { return 3.14 * r * r; }  // 明確重寫
private:double r;
};

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

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

相關文章

數學復習筆記 29 不定積分

前言 復習的時候時常復習一下以前復習的高數&#xff0c;溫故而知新&#xff0c;可以為師矣。現實生活中有非常多讓我難受的事情&#xff0c;賢者模式的時候也會對一些自己的行為嗤之以鼻&#xff0c;復習考研對其他三門科目都沒有學出來正反饋&#xff0c;只能從數學這兒找一…

微軟因安全漏洞禁用黑暗環境下的Windows Hello面部識別功能

面部識別技術在各種場景中的應用日益廣泛&#xff0c;但身份欺詐事件仍時有發生&#xff0c;這表明即使面部識別也并非萬無一失。在某些情況下&#xff0c;這些系統可能被攻擊者利用。 漏洞發現與應對措施 近期&#xff0c;微軟在Windows 10和11系統中禁用了黑暗環境下使用Wi…

產品經理課程(十五)實戰點評(3)

&#xff08;一&#xff09;復習 需求文檔是產品的說明書 需求文檔包含&#xff1a;修訂記錄、背景、主要流程、詳細功能邏輯、數據上報&#xff0c;發布策略 bug也是需求文檔的一部分 &#xff08;二&#xff09;案例講解 案例一&#xff1a; 一個版本里面的4-5個功能點就比…

大模型量化與剪枝

大模型量化&#xff0c;剪枝 量化有助于減少顯存使用并加速推理 GPTQ 等后訓練量化方法(Post Training Quantization)是一種在訓練后對預訓練模型進行量化的方法。 ### model model_name_or_path: meta-llama/Meta-Llama-3-8B-Instruct template: llama3### export export_di…

Oracle 數據庫數據操作:精通 INSERT, UPDATE, DELETE

作者&#xff1a;IvanCodes 日期&#xff1a;2025年6月18日 專欄&#xff1a;Oracle教程 在 Oracle 數據庫中&#xff0c;對表內數據進行增加、修改和刪除操作是通過數據操作語言 (DML - Data Manipulation Language) 來完成的。核心的DML語句包括 INSERT (插入新數據), UPDATE…

推薦使用的Unity插件(InputSystem)

本文將提供更簡潔的步驟和常見問題解決。 一、極簡入門步驟&#xff1a; 安裝&#xff1a;Package Manager中安裝Input System&#xff08;確保Unity版本在2019.4&#xff09; 創建Input Actions&#xff1a; 在Project窗口右鍵 -> Create -> Input Actions 雙擊打開…

清理 Docker 容器日志文件方法

操作總結與問題解析 一、操作目的與背景 用戶旨在清理 Docker 容器日志文件以釋放服務器存儲空間,主要通過以下命令組合完成操作: 查看容器日志空間占用清空指定容器的日志文件驗證容器運行狀態與日志清理效果二、關鍵命令與輸出解析 1. 查看 Docker 容器日志空間占用 du…

圖片壓縮工具 | 按指定高度垂直切割圖片

OPEN-IMAGE-TINY&#xff0c;一個基于 Electron VUE3 的圖片壓縮工具&#xff0c;項目開源地址&#xff1a;https://github.com/0604hx/open-image-tiny ?? 需求描述 在上一篇文章一段代碼利用 snapdom 將 CSDN 博文轉化為長圖片&#xff08;PNG/JPG/PDF&#xff09;中&…

山東大學軟件學院創新項目實訓開發日志——第十七周(二)

目錄 1.優化前端日歷頁面顯示&#xff0c;增加鼠標懸停顯示當日會議基本信息的效果。 2.優化會議計劃生成與會議PPT生成功能&#xff0c;使得能夠加載多頁docx文件與PDF文件 3.優化了會議PPT生成功能&#xff0c;使得可以上傳多個文件并根據多個文件生成會議PPT 4.修改了識…

Ubuntu 使用kubeadm部署k8s系統組件反復重啟的問題

系統&#xff1a;Ubuntu 24.04 LTS 問題現象&#xff1a;kubeadm init 后系統組件proxy、apiserver、etcd等頻繁掛掉重啟 問題原因&#xff1a;cgroup配置問題 解決方法&#xff1a; 編輯系統cgroup默認配置文件 sudo nano /etc/default/grub 將GRUB_CMDLINE_LINUX_DEFAU…

Oracle獲取執行計劃之EXPLAIN PLAN 技術詳解

#Oracle #執行計劃 #EXPLAIN PLAN 一、引言 在Oracle數據庫性能優化中&#xff0c;?執行計劃&#xff08;Execution Plan&#xff09;?是理解SQL語句如何被數據庫處理的關鍵工具。EXPLAIN PLAN是Oracle提供的一種靜態分析SQL執行路徑的方法&#xff0c;它通過生成邏輯執行…

【論文閱讀】Qwen2.5-VL Technical Report

Arxiv:https://arxiv.org/abs/2502.13923 Source code:https://github.com/QwenLM/Qwen2.5-VL Author’s Institution&#xff1a;Alibaba 背景 多模態大模型 多模態大模型MultiModal Large Language Models (MM-LLMs) 的發展可以通過一篇綜述了解&#xff1a;MM-LLMs: Re…

vue中computed和watch區別

在 Vue 中&#xff0c;computed 和 watch 都是用來響應式地處理數據變化的工具&#xff0c;但它們的用途和行為有明顯區別。 &#x1f50d; 一句話總結 computed&#xff1a;用于聲明式計算屬性&#xff0c;有緩存。 watch&#xff1a;用于監聽響應式數據的變化并執行副作用邏…

大語言模型:提示詞決定自我反思效果: “檢查回答是否錯誤” “驗證回答是否正確”

大語言模型(LLMs)自我反思的結果很容易受提示詞構造的影響 大型語言模型(LLMs)展現出令人印象深刻的零樣本和少樣本推理能力。有人提出,這些能力可以通過自我反思來提升,即讓大型語言模型反思自己的輸出,以識別和糾正初始回答中的錯誤。然而,盡管有一些證據表明自我反…

【iReport】實際開發中,解決iReport中打印圖片不顯示問題

ireport 中增加圖片&#xff0c;添加上屬性&#xff0c;但是運行時報錯如下&#xff0c;是屬性logoPath沒有聲明到map中 1. Parameter not found : logoPath net.sf.jasperreports.engine.design.JRValidationException: Report design not valid : 1. Parameter not fo…

【MySQL進階】常用MySQL程序

目錄 一. mysqlcheck——表維護程序 1.1.作用 1.2 注意事項 1.3 使用方法 1.4 常用選項 1.5 mysqlcheck的特殊使用 二. mysqldump——數據庫備份程序 2.1.作用 2.2 注意事項 2.3 使用方法 2.4 常用選項 三. mysqladmin——MySQL 服務器管理程序 3.1.作用 3.2 使用…

EMQX高效存儲消息到MySQL指南

配置 EMQX 存儲消息到 MySQL EMQX 可以通過規則引擎和數據橋接功能將消息和事件存儲到 MySQL 數據庫。以下是具體實現方法&#xff1a; 創建 MySQL 數據表 在 MySQL 中創建用于存儲消息的表結構&#xff1a; CREATE TABLE mqtt_messages (id int(11) NOT NULL AUTO_INCREME…

springboot項目,利用docker打包部署

Windows WSL2 Docker Desktop 部署 SpringBoot 項目指南 &#xff08;沒有安裝docker的&#xff0c;如果是windows家庭中文版的&#xff0c;可以看我上一篇帖子&#xff1a;windows家庭版安裝docker和redis-CSDN博客&#xff09; 本教程將說明如何在 Windows 系統 下&#…

MO+內核32位普冉單片機PY32F003開發板

PY32F003開發板是基于普冉半導體PY32F003微控制器設計的低成本入門級開發工具&#xff0c; PY32F003系列微控制器采用高性能的 32 位ARM Cortex-M0內核&#xff0c;寬電壓工作范圍的 MCU。嵌入高達32Kbytes flash 和 4Kbytes SRAM 存儲器&#xff0c;最高工作頻率 32MHz。PY32…

MySql 用存儲過程刪除所有用戶表

用拼接語句總是會出問題 -- 1. 禁用外鍵約束&#xff08;防止級聯刪除失敗&#xff09;[1]() SET SESSION FOREIGN_KEY_CHECKS 0; -- 2. 生成并執行刪除語句&#xff08;替換 your_database_name&#xff09; SELECT CONCAT(DROP TABLE IF EXISTS , TABLE_NAME, ;) -- 預覽語…