C++語言編程規范-初始化和類型轉換

01??

C++語言編程規范-常量

02??

初始化和類型轉換

聲明、定義與初始化

03??

禁止用 memcpy、memset 初始化非 POD 對象

說明:POD 全稱是“Plain Old Data”,是 C++ 98 標準(ISO/IEC 14882, first edition, 1998-09-01)中引入的一個概念, POD 類型主要包括?int, char, float,double,enumeration,void指針等原始類型及其集合類型,不能使用封裝和面對對象特性(如用戶定義的構造/賦值/析構函數、基類、虛函 數等)。

由于非 POD 類型比如非集合類型的 class 對象,可能存在虛函數,內存布局不確定,跟編譯器有關,濫用內存拷貝可能會導致嚴重的問題。 即使對集合類型的 class,使用直接的內存拷貝和比較,破壞了信息隱蔽和數據保護的作用,也不提倡 memcpy、memset 操作。

示例:×××產品程序異常退出(core dump)。 經過現場環境的模似,程序產生 COREDUMP,其原因是:

在初始化函數內使用

    ?memset(this,0,sizeof(*this))

    進行了類的初始化,將類的虛函數表指針被清空,從而導致使用空指針。

    解決方案:使用 C++構造函數初始化,不要使用 memset 函數初始化類對象。

    04??

    變量使用時才聲明并初始化

    說明:變量在使用前未賦初值,是常見的低級編程錯誤。使用前才聲明變量并同時初始化,非常方便 地避免了此類低級錯誤。在函數開始位置聲明所有變量,后面才使用變量,作用域覆蓋整個函數實現,容易導致如下問題:

    ? 程序難以理解和維護:變量的定義與使用分離。

    ? 變量難以合理初始化:在函數開始時,經常沒有足夠的信息進行變量初始化,往往用某個默認的空值(比如零)來初始化,這通常是一種浪費,如果變量在被賦于有效值以前使用,還會導致錯誤。遵循變量作用域最小化原則與就近聲明原則,使得代碼更容易閱讀,方便了解變量的類型和初始值。特別是,應使用初始化的方式替代聲明再賦值。

    示例:

      //不好的例子:聲明與初始化分離string?name;?//聲明時未初始化:調用缺省構造函數//…….?name=”zhangsan”;?//再次調用賦值操作符函數;聲明與定義在不同的地方,理解相對困難//好的例子:聲明與初始化一體,理解相對容易string?name(”zhangsan”);?//調用一次構造函數

      05??

      避免構造函數做復雜的初始化,可以使用“init”函數

      說明:正如函數的變量都在函數內部初始化一樣,類數據成員最好的初始化場所就是構造函數,數據成員都應該盡量在構造函數中初始化。

      以下情況可以使用?init()函數來初始化:

      ? 需要提供初始化返回信息。

      ? 數據成員初始化可能拋異常。

      ? 數據成員初始化失敗會造成該類對象初始化失敗,引起不確定狀態。

      ??數據成員初始化依賴 this 指針:構造函數沒結束,對象就沒有構造出來,構造函數內不能使用 this 成員;

      ? 數據成員初始化需要調用虛函數。在構造函數和析構函數中調用虛函數,會導致未定義的行為。

      示例:數據成員初始化可能拋異常:

        class?CPPRule?{public:?? CPPRule():size_(0), res (null) {};?//僅進行值初始化??long?init(int?size)?? {?? ??//根據傳入的參數初始化size_, 分配資源res?? }?private:???int?size_;?? ResourcePtr* res;?};?//使用方法:CPPRule a;?a.init(100);

        06??

        初始化列表要嚴格按照成員聲明順序來初始化它們

        說明:編譯器會按照數據成員在類定義中聲明的順序進行初始化,而不是按照初始化列表中的順序,

        如果打亂初始化列表的順序實際上不起作用,但會造成閱讀和理解上的混淆;特別是成員變量之間存在依賴關系時可能導致 BUG。

        示例:

          //不好的例子:初始化順序與聲明順序不一致class?Employee?{?public:?Employee(const?char* firstName,?const?char* lastName)?: firstName_(firstName), lastName_(lastName)?, email_(firstName_ +?"."?+ lastName_ +?"@huawei.com") {};?private:?string?email_, firstName_, lastName_;?};

          類定義 email_是在 firstName_,lastName_之前聲明,它將首先初始化,但使用了未初始化的 firstName_和lastName_,導致錯誤。在成員聲明時,應按照成員相互依賴關系按順序聲明。

          07??

          類型轉換

          避免使用類型分支來定制行為:類型分支來定制行為容易出錯,是企圖用 C++編寫 C 代碼的明顯標志。

          這是一種很不靈活的技術,要添加新類型時,如果忘記修改所有分支,編譯器也不會告知。使用模板和虛函數,讓類型自己而不是調用它們的代碼來決定行為。

          08??

          使用 C++風格的類型轉換,不要使用 C 風格的類型轉換

          說明:C++的類型轉換由于采用關鍵字,更醒目,更容易查找,編程中強迫程序員多停留思考片刻,謹慎使用強制轉換。

          C++使用?const_cast, dynamic_cast, static_cast, reinterpret_cast?等新的類型轉換,它們允許用戶選擇適當級別的轉換符,而不是像 C 那樣全用一個轉換符。

          dynamic_cast:主要用于下行轉換,dynamic_cast 具有類型檢查的功能。dynamic_cast 有一定的開銷,建議在調測代碼中使用。

            #include?<iostream>#include<typeinfo>class?Base?{public:? ??virtual?~Base() {}?// 需要虛函數才能啟用RTTI};class?Derived?:?public?Base {public:? ??void?derived_func()?{? ? ? ? std::cout <<?"Derived function called"?<< std::endl;? ? }};int?main()?{? ? Base* base_ptr =?new?Derived();? ??// 使用 dynamic_cast 進行安全的下行轉換? ? Derived* derived_ptr =?dynamic_cast<Derived*>(base_ptr);? ??if?(derived_ptr) {? ? ? ? std::cout <<?"轉換成功"?<< std::endl;? ? ? ? derived_ptr->derived_func();?// 安全調用派生類函數? ? }?else?{? ? ? ? std::cout <<?"轉換失敗"?<< std::endl;? ? }? ??// 嘗試轉換不匹配的類型? ? Derived* another_ptr =?dynamic_cast<Derived*>(new?Base());? ??if?(another_ptr) {? ? ? ? std::cout <<?"轉換成功"?<< std::endl;? ? }?else?{? ? ? ? std::cout <<?"轉換失敗"?<< std::endl;? ? }? ??delete?base_ptr;? ??delete?another_ptr;? ??return?0;}

            對于引用類型的 dynamic_cast:

              #include<iostream>#include?<typeinfo>class?Base?{public:? ??virtual?~Base() {}};class?Derived?:?public?Base {public:? ??void?derived_func()?{? ? ? ? std::cout <<?"Derived function called"?<< std::endl;? ? }};void?process(Base& base)?{? ??try?{? ? ? ? Derived& derived =?dynamic_cast<Derived&>(base);? ? ? ? std::cout <<?"轉換成功"?<< std::endl;? ? ? ? derived.derived_func();? ? }?catch?(const?std::bad_cast& e) {? ? ? ? std::cout <<?"轉換失敗: "?<< e.what() << std::endl;? ? }}int?main()?{? ? Derived derived;? ? Base base;? ? std::cout <<?"處理 Derived 對象:"?<< std::endl;? ??process(derived);?// 轉換成功? ? std::cout <<?"\n處理 Base 對象:"?<< std::endl;? ??process(base); ? ?// 轉換失敗? ??return?0;}

              static_cast:和 C 風格轉換相似可做值的強制轉換,或上行轉換(把派生類的指針或引用轉換成基類的指針或引用)。該轉換經常用于消除多重繼承帶來的類型歧義,是相對安全的。下行轉換(把基類的

              指針或引用轉換成派生類的指針或引用)時,由于沒有動態類型檢查,所以不安全的,不提倡下行轉換。

              上行轉換(派生類到基類)- 這是 static_cast 最安全的用法之一

                class?Base?{public:? ??virtual?~Base() {}? ??virtual?void?base_func()?{ std::cout <<?"Base function"?<< std::endl; }};class?Derived?:?public?Base {public:? ??void?derived_func()?{ std::cout <<?"Derived function"?<< std::endl; }};int?main()?{? ? Derived derived;? ? Base* base_ptr =?static_cast<Base*>(&derived);?// 上行轉換,安全? ? base_ptr->base_func();?// 調用基類函數? ??return?0;}

                reinterpret_cast:用于轉換不相關的類型。reinterpret_cast 強制編譯器將某個類型對象的內存新解釋成另一種類型,相關代碼可移植不好。建議對 reinterpret_cast<>的用法進行注釋,有助于減少維

                護者在看到這種轉換時的顧慮。

                良好的編碼實踐:添加注釋

                  // 注意:這里使用 reinterpret_cast 是因為我們需要將特定內存區域// 解釋為另一種類型,這是平臺相關的操作,不具有可移植性class?MemoryMappedDevice?{public:? ??MemoryMappedDevice(void* base_addr)?? ? ? ? :?control(reinterpret_cast<volatile?uint32_t*>(base_addr)),? ? ? ? ??data(reinterpret_cast<volatile?uint32_t*>(static_cast<uintptr_t>(base_addr) +?4)) {}private:? ??volatile?uint32_t* control;? ??volatile?uint32_t* data;};

                  const_cast:用于移除對象的 const 屬性,使對象變得可修改。

                    int?main()?{? ??const?int?ci =?10;? ??const?int* ci_ptr = &ci;? ??// 移除 const 屬性? ??int* i_ptr =?const_cast<int*>(ci_ptr);? ? *i_ptr =?20;?// 現在可以修改值? ? std::cout <<?"ci: "?<< ci << std::endl;?// 輸出可能是 20,也可能還是 10? ? std::cout <<?"*i_ptr: "?<< *i_ptr << std::endl;?// 輸出 20? ??return?0;}

                    09??

                      extern?void?Fun(DerivedClass* pd);?void?Gun(BaseClass* pb)?{?//不好的例子: C風格強制轉換,轉換會導致對象布局不一致,編譯不報錯,運行時可能會崩潰DerivedClass* pd = (DerivedClass *)pb;?//好的例子: C++風格強制轉換,明確知道pb實際指向DerivedClass?DerivedClass* pd = dynamic_cast< DerivedClass *>(pb);?if(pd)?Fun(pd);}

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

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

                      相關文章

                      從零構建一款開源在線客服系統:我的Go語言實戰之旅

                      了解更多&#xff0c;搜索 "程序員老狼"用代碼連接世界&#xff0c;讓溝通無界限緣起&#xff1a;為什么選擇開發客服系統&#xff1f;在數字化浪潮席卷全球的今天&#xff0c;企業與客戶之間的溝通方式正在發生深刻變革。傳統的電話和郵件支持已無法滿足即時互動的需…

                      unsloth筆記:基本介紹

                      更快的速度、更省的內存訓練、運行、評估大模型 1 支持的模型 All Our Models | Unsloth Documentation 1.1 Dynamic GGUF/instruct 4-bit llama.cpp使用的新模型格式&#xff0c;專為高效、本地推理設計注&#xff1a;GGUF無法微調 只保留推理所需的內容&#xff0c;如量化…

                      博眾測控 | 一文看懂菊水電源產品在半導體測試中的應用

                      01 半導體在各行業上的應用半導體作為現代工業體系的“核心神經”&#xff0c;其性能參數與應用場景深度綁定&#xff0c;不同行業因核心設備的功能需求差異&#xff0c;對半導體的電流、電壓承載能力及類型選擇有著明確且嚴格的要求&#xff0c;具體應用細節如下&#xff1a;1…

                      【STM32】貪吃蛇 [階段 8] 嵌入式游戲引擎通用框架設計

                      這篇博客是 承接&#xff1a;【項目思維】貪吃蛇&#xff08;嵌入式進階方向&#xff09;中 嵌入式游戲引擎雛形&#xff08;終極進階&#xff09;&#xff0c; 是我們此前從 “寫一個小游戲”提升到“構建可復用游戲框架” 的飛躍階段。我們以“貪吃蛇游戲”為例&#xff0c;抽…

                      Vue圖標按鈕好用的樣式

                      圖標按鈕示例一 <template><div class"icon-button-group"><button class"icon-btn icon-btn--default"><i class"el-icon-moon"></i></button><button class"icon-btn icon-btn--primary"&g…

                      Nginx 實戰系列(一)—— Web 核心概念、HTTP/HTTPS協議 與 Nginx 安裝

                      文章目錄前言一、Web 概念1.1 Web 的基本概念1.1.1 Web的特點1.2 B/S 架構模型1.3 Web 請求與響應過程&#xff08;重點&#xff09;1.4 靜態資源與動態資源1.5 Web 的發展階段1.6 案例&#xff1a;搭建最小 Web 服務1.6.1 目標1.6.2 搭建步驟1.7 小結二、HTTP 與 HTTPS 協議2.…

                      一種用geoserver發布復雜樣式矢量服務的方法

                      最近因為系統需要在國產系統中部署&#xff0c;遇見了國產系統不支持ArcGIS的尷尬局面&#xff0c;好在geoserver還是可以支持的&#xff0c;遂用geoserver解決服務問題。 在發布過程中&#xff0c;遇到比較難受的點就是矢量數據的樣式配圖&#xff0c;在我用QGIS配好導出sld后…

                      為什么神經網絡網絡算法比機器學習模型算法更加強大?

                      神經網絡&#xff08;尤其是深度神經網絡&#xff09;相比傳統機器學習模型&#xff08;如線性回歸、決策樹、支持向量機等&#xff09;的“強大”主要體現在其更強的表達能力、自適應特征學習能力以及對復雜模式的建模能力。但這種“強大”并非絕對&#xff0c;而是有特定條件…

                      中國移動浪潮云電腦CD1000-系統全分區備份包-可瑞芯微工具刷機-可救磚

                      中國移動浪潮云電腦CD1000-系統全分區備份包-可瑞芯微工具刷機-可救磚 開啟ADB教程&#xff1a; 可查看&#xff1a;浪潮CD1000-移動云電腦-RK3528芯片-232G-安卓9-開啟ADB ROOT破解教程 可輕松打開了wifi adb和USB調試。 往期詳細內容-文章&#xff1a;浪潮CD1000-移動云電腦…

                      C++兩個字符串的結合

                      這段代碼實現字符串拼接功能。用戶輸入兩個字符串a和b后&#xff0c;使用append()方法將b追加到a后面&#xff0c;然后輸出拼接后的結果。代碼簡潔但存在改進空間&#xff1a;1. 缺少輸入驗證 2. 直接修改原字符串a可能不符合某些場景需求 3. 可考慮更高效的拼接方式。適合基礎…

                      UE4 Rider調試時添加自定義命令行參數

                      1、打開 Rider 右上角&#xff0c;針對你的項目&#xff08;例如叫做“Mini”&#xff09;打開 Edit 2、輸入自定義的參數&#xff0c;如下圖的例子是輸入 -dx12 -norhithread &#xff0c;然后Apply并OK。3、開始調試&#xff08;蟲子按鈕&#xff09;

                      混合架構大型語言模型(Jamba)

                      Jamba是由AI21 Labs開發的混合架構大型語言模型&#xff08;LLM&#xff09;&#xff0c;結合了Transformer的語義理解能力和Mamba結構化狀態空間模型&#xff08;SSM&#xff09;的高效性&#xff0c;旨在解決長文本處理中的計算瓶頸。 一、技術特點 1.混合架構設計 Jamba采用…

                      2025 年高教社杯全國大學生數學建模競賽C 題 NIPT 的時點選擇與胎兒的異常判定詳解(一)

                      基于胎兒Y染色體濃度的孕周與BMI建模分析摘要本文利用某競賽提供的胎兒Y染色體濃度數據&#xff0c;建立了以孕周和孕婦BMI為自變量的多項式回歸模型&#xff0c;探討了其對Y染色體濃度的影響。通過數據清洗與篩選&#xff0c;共獲得1082條有效男胎樣本。結果顯示&#xff1a;Y…

                      PyTorch DDP 隨機卡死復盤:最后一個 batch 掛起,NCCL 等待不返回

                      PyTorch DDP 隨機卡死復盤&#xff1a;最后一個 batch 掛起&#xff0c;NCCL 等待不返回&#xff0c;三步修復 Sampler & drop_last很多人在接觸深度學習的過程往往都是從自己的筆記本開始的&#xff0c;但是從接觸工作后&#xff0c;更多的是通過分布式的訓練來模型。由于…

                      計算機專業考研備考建議

                      對于全國碩士研究生招生考試&#xff08;考研&#xff09;&#xff0c;考試科目主要由兩大部分組成&#xff1a;全國統一命題的公共課 和 由招生單位自主命題的專業課。具體的考試科目取決于你報考的專業和學校。下面我為你詳細拆解&#xff1a;一、考試科目構成&#xff08;絕…

                      關于嵌入式學習——單片機1

                      基礎整體概念以應用為中心:消費電子(手機、藍牙耳機、智能音響)、醫療電子(心率脈搏、呼吸機)、無人機(大疆D)、機器人(人形四足機器人) 計算機技術:計算機五大組成:運算器(數據運算)、控制器(指令控制)、存儲器(內存外存)、輸入設備(鼠標、鍵盤、攝像頭)、輸出設備(顯示器)軟件…

                      LightDock.server liunx 雙跑比較

                      LightDock: a new multi-scale approach to protein–protein docking The LightDock server is free and open to all users and there is no login requirement server 1示例 故去除約束 next step 結果有正有負合理 2.常見警告? Structure contains HETATM entries. P…

                      SQL面試題及詳細答案150道(61-80) --- 多表連接查詢篇

                      《前后端面試題》專欄集合了前后端各個知識模塊的面試題,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。 前后端面試題-專欄總目錄 文章目錄 一、本文面試題目錄 61. 什么是內連接(INNE…

                      【實操】Noej4圖數據庫安裝和mysql表銜接實操

                      目錄 一、圖數據庫介紹 二、安裝Neo4j 2.1 安裝java環境 2.2 安裝 Neo4j&#xff08;社區版&#xff09; 2.3 修改配置 2.4 驗證測試 2.5 卸載 2.6 基本用法 2.7 windows連接服務器可視化 三、neo4j和mysql對比 3.1 場景對比 3.2 Mysql和neo4j的映射對比 3.3 mys…

                      【mysql】SQL查詢全解析:從基礎分組到高級自連接技巧

                      SQL查詢全解析&#xff1a;從基礎分組到高級自連接技巧詳解玩家首次登錄查詢的多種實現方式與優化技巧在數據庫查詢中&#xff0c;同一個需求往往有多種實現方式。本文將通過"查詢每個玩家第一次登錄的日期"這一常見需求&#xff0c;深入解析SQL查詢的多種實現方法&a…