More Effective C++:改善編程與設計(下)

目錄

條款19:了解臨時對象的來源

條款20:協助完成“返回值優化”

條款21:利用重載技術避免隱式類型轉換

條款22:考慮以操作符復合形式(op=)取代其獨身形式(op)

條款23:考慮使用其他程序庫

條款24:了解virtual functions、multiple inheritance、virtual base classes、runtime type identification的成本

條款25:將constructors和non-member functions虛化

條款26:限制某個class所能產生的對象數量

條款27:要求(禁止)對象產生于heap之中

條款28:智能指針(smart pointers)


條款19:了解臨時對象的來源

????????產生臨時對象通常發生于兩種情況:
????????一是當隱式類型轉換時,但請注意其中涉及到引用權限的問題,如果發生隱式類型轉換,產生的臨時變量具有常性,那么不能使用non-const類型進行接受,這屬于權限放大;
????????二是當函數返回對象,需要進行返回值優化,
總結:臨時對象很耗成本,因此你需要盡可能消除它們。

條款20:協助完成“返回值優化”

????????如果返回值在函數棧楨回收時銷毀,那么你不能使用引用返回或者指針返回,此時取別名或是指針指向的是一個已經死亡的對象,沒有任何意義,但如果出了函數作用域仍然沒有銷毀,那么可以考慮使用引用返回的方式。 如果函數一定要以by-value的方式返回對象,你無法 消除之,在不同的場景你需要選擇正確且高效的返回值優化方式。
總結:在不同的場景你需要選擇正確且高效的返回值優化方式。如果一定要傳值返回,請不要刻意優化。

條款21:利用重載技術避免隱式類型轉換

????????單參數的構造函數支持隱式類型轉換, 那么這里建議你單獨重載一個函數來進行特殊傳 參,而不掉用隱式構造函數, 同時,請不要忘記增加太多的重載函數會影響程序效率。

條款22:考慮以操作符復合形式(op=)取代其獨身形式(op)

????????第一, 一般而言,復合操作符比其對應的獨身版本效率高, 因為獨身版本通常必須返回一個新對象,而我們必須因此負擔一個臨時對象的構造和析構的成本,至于復合版本則是直接將結果寫入其左端自變量,所以不需要產生一個臨時對象來放置返回值。
????????第二, 獨身版本較易撰寫,調試,和維護,方便使用, 復合版本效率較高,你可以同時提供兩個版本,并根據性能與便利性自由選擇。

條款23:考慮使用其他程序庫

????????不同的程序庫即使提供相似的機能,也往往表現出不同的性能取舍策略,所以一旦你找出程序的瓶頸,你應該思考是否有可能因為改用另一個程序庫而移除了那些瓶頸,可以找找看是否存在另一個功能相近的程序庫而其在效率上有較高的設計權重。如果有,改用它,可以大幅 改善程序性能。

條款24:了解virtual functions、multiple inheritance、virtual base classes、runtime type identification的成本

????????當一個虛函數被調用時,編譯器使用virtual tables和virtual table pointers(簡寫為vtbls和vptrs)。vtbl通常是一個函數指針數組,其中保存的是各個虛函數的函數指針, 使用虛函數的成本是一個vtbl數組空間以及一個額外指針vptr,以及類中的成員函數都有inline的屬性,那么使用虛函數事實上等于放棄了inlining。 (如果虛函數通過對象被調用,倒是可以inlined,但大部分虛函數調用動作是通過對象的指針或者引用完成的,此類行為無法被inlined。) ?
????????上面是簡單繼承,再來看看多重繼承,舉例菱形繼承,為了不引發二義性使用虛擬繼承:
????????如圖所示,虛基類可能導致對象內的隱藏指針增加,而如果基類A有任何虛函數,內存布局會
增加更多的指針(用紅筆標出)。

條款25:將constructors和non-member functions虛化

????????這里說的當然不是將真正的構造函數虛化,如果你真的這么做了就會出大問題,由于虛函數 表是在初始化列表進行初始化的,那么如果你對函數進行虛化,那么需要先產生虛函數表,但虛 函數表在構造函數內部產生,這會導致程序混亂。好了, 這里是指將重復進行構造的動作單獨設為一個函數,將此函數進行虛化,那么不同對象的構造函數來調用此函數就可以產生偽構造函數虛化的效果。
????????就像constructors無法真正被虛化一樣。non-member functions也是,就像我們認為應該能夠以某個函數構造出不同類型的新對象一樣,我們也認為應該可以讓non-member functions的行為視其參數的動態類型而不同。

條款26:限制某個class所能產生的對象數量

????????允許零個或一個對象:每當產生一個對象,就會調用這個class的構造函數,而阻止某個
class產出對象的最簡單的方法就是將其constructors聲明為private:
????????Class myclass
????????{
?????????private:
????????????????myclass();
????????????????myclass(const myclass& mc);
????????}
????????但這樣移除了每個人產出對象的權利,但我們也可以選擇性地解除這項約束,單例模式可以分為: 餓漢模式以及懶漢模式,前者不管怎么樣都會生成一份對象,且存在初始化順序混亂的問
題,而后者可以在必要時進行初始化,節省空間, 大致方式是將類的對象和create函數設為
static,將構造函數隱藏,在create函數中調用構造函數來進行初始化…
//這里作者模擬實現了一下:僅供參考
namespace hungry
{class Singleton{public:static Singleton& Create(){return slt;}bool Add(const pair<string, string>& kv){hash.insert(kv);return true;}void print(){for (const auto& e : hash){cout << e.first << " " << e.second << endl;}}private://先將構造函數私有化,防止輕易構造新對象Singleton(){}//以hash表為例子unordered_map<string, string> hash;//如何確保只有一個對象?使用staticstatic Singleton slt;//!!!記住要防止拷貝Singleton& operator=(const Singleton& st) = delete;Singleton(const Singleton& st) = delete;};Singleton Singleton::slt;//這里有點小奇怪,就理解為用singleton實例化singletion的slt吧
}//懶漢模式:直接用指針代替,需要的時候再進行實例化
namespace lazy
{class Singleton{public:static Singleton& Create(){if (slt == nullptr){slt = new Singleton;return *slt;}else{return *slt;}}// 一般單例不用釋放。// 特殊場景:1、中途需要顯示釋放  2、程序結束時,需要做一些特殊動作(如持久化),比如寫入文件static void Delete(){if (slt){delete slt;slt = nullptr;}else return;}bool Add(const pair<string, string>& kv){hash.insert(kv);return true;}void print(){for (const auto& e : hash){cout << e.first << " " << e.second << endl;}}class GC{public:~GC(){//垃圾回收站,這是為了方便多個單例對象需要持久化或者手動釋放使用的Singleton::Delete();}};private://先將構造函數私有化,防止輕易構造新對象Singleton(){}~Singleton(){//在這里可以做一些持久化操作,將數據寫入文件cout << "destructor" << endl;}unordered_map<string, string> hash;static Singleton* slt;static Singleton::GC gc;Singleton& operator=(const Singleton& st) = delete;Singleton(const Singleton& st) = delete;};Singleton* Singleton::slt=nullptr;Singleton::GC Singleton::gc;
}
????????不同的對象構造狀態:你可以使用繼承的方式實現不同對象的不同構造,但是要小心內存
泄露,可以使用智能指針來管理對象。

條款27:要求(禁止)對象產生于heap之中

????????允許對象產生于heap中:(禁止產生于棧中)
????????有兩種方法:1.將析構函數私有,這樣無法直接實例化出對象;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.將構造函數私有,使用static Create函數來執行new operator操作返回指針;
//只能在堆上實例化
class Heaponly1
{
public:Heaponly1(){ }void Delete(){delete this;//巧妙}private:~Heaponly1(){//...}//要防止在棧上創建空間,還要將拷貝構造和復制構造deleteHeaponly1& operator=(const Heaponly1& hp) = delete;Heaponly1(const Heaponly1& hp) = delete;
};class Heaponly2
{
public:static Heaponly2* Create(){return new Heaponly2;}
private:Heaponly2(){//...}Heaponly2& operator=(const Heaponly2& hp) = delete;Heaponly2(const Heaponly2& hp) = delete;
};
????????禁止對象產生于heap中:(允許產生于棧中)
????????有兩種方法:1.將operator new函數delete,這樣new operator就無法調用operator new;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.將構造函數私有,使用static Create函數來在棧上產生一個對象,并返回引用;
//只能在棧上創建對象的類
class Stackonly1
{
public:static Stackonly1 Create(){Stackonly1 st;return st;}
private:Stackonly1(){}
};class Stackonly2
{
public:Stackonly2(){ }
private:void* operator new(size_t size) = delete;
};

條款28:智能指針(smart pointers)

????????智能指針有auto_ptr、unique_ptr、shared_ptr、weak_ptr,其中auto_ptr存在指針懸空的 問題,unique_ptr只能管理一個對象,進行了反拷貝操作,shared_ptr使用引用計數,當計數減為0時釋放內存,但是存在引用循環的問題,所以weak_ptr來專門解決引用循環的問題,不參與計數的改變,具體模擬實現可以參考作者往作。
C++ 智能指針底層邏輯揭秘:優化內存管理的核心技術解讀-CSDN博客https://blog.csdn.net/Dai_renwen/article/details/147230673?spm=1001.2014.3001.5501

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

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

相關文章

VTK|類似CloudCompare的比例尺實現2-vtk實現

文章目錄 實現類頭文件實現類源文件調用邏輯關鍵問題縮放限制問題投影模式項目git鏈接實現類頭文件 以下是對你提供的 ScaleBarController.h 頭文件添加詳細注釋后的版本,幫助你更清晰地理解每個成員和方法的用途,尤其是在 VTK 中的作用: #ifndef SCALEBARCONTROLLER_H #de…

PostgreSQL 聯合索引生效條件

最近面試的時候&#xff0c;總會遇到一個問題 在 PostgreSQL 中&#xff0c;聯合索引在什么條件下會生效&#xff1f; 特此記錄~ 前置信息 數據庫版本 PostgreSQL 14.13, compiled by Visual C build 1941, 64-bit 建表語句 CREATE TABLE people (id SERIAL PRIMARY KEY,c…

SpringBoot項目里面發起http請求的幾種方法

在Spring Boot項目中發起HTTP請求的方法 在Spring Boot項目中&#xff0c;有幾種常用的方式可以發起HTTP請求&#xff0c;以下是主要的幾種方法&#xff1a; 1. 使用RestTemplate (Spring 5之前的主流方式) // 需要先注入RestTemplate Autowired private RestTemplate restT…

《Python星球日記》 第90天:微調的概念以及如何微調大模型?

名人說:路漫漫其修遠兮,吾將上下而求索。—— 屈原《離騷》 創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder??) 目錄 一、微調原理1. 什么是大模型微調?2. 為什么需要微調?3. 微調的基本流程4. 微調策略分類二、LoRA(Low-Rank Adaptation)技術詳解1. LoRA的核…

機器學習-人與機器生數據的區分模型測試 - 模型融合與檢驗

模型融合 # 先用普通Pipeline訓練 from sklearn.pipeline import Pipeline#from sklearn2pmml.pipeline import PMMLPipeline train_pipe Pipeline([(scaler, StandardScaler()),(ensemble, VotingClassifier(estimators[(rf, RandomForestClassifier(n_estimators200, max_de…

怎樣免費開發部署自己的網站?

要免費開發自己的網站&#xff0c;您可以根據自己的技術水平和需求選擇以下兩種主要方式&#xff1a; 零基礎用戶&#xff1a;建議使用如WordPress.com、Weebly、Strikingly等平臺&#xff0c;快速搭建網站。 有一定技術基礎的用戶&#xff1a;可選擇自行開發網站&#xff0c;…

調用百度云API機器翻譯

新建Python文件&#xff0c;叫 text_translator.py 輸入 import requests import jsonAPI_KEY "glYiYVF2dSc7EQ8n78VDRCpa" # 替換為自己的API Key SECRET_KEY "kUlhze8OQZ7xbVRp" # 替換為自己的Secret Keydef main():# 選擇翻譯方向while True:di…

OpenAI與微軟洽談新融資及IPO,Instagram因TikTok流失四成用戶

OpenAI與微軟洽談新融資及IPO 據悉&#xff0c;OpenAI 正與微軟洽談新融資及籌備 IPO&#xff0c;關鍵問題是微軟在 OpenAI 重組后的股權比例。微軟已投資超 130 億美元&#xff0c;雙方修訂 2019 年合同&#xff0c;微軟擬棄部分股權換新技術訪問權。OpenAI 上周放棄了有爭議轉…

git工具使用詳細教程-------命令行和TortoiseGit圖形化

下載 git下載地址&#xff1a;https://git-scm.com/downloads TortoiseGit&#xff08;圖形化工具&#xff09;下載地址&#xff1a;https://tortoisegit.org/download/ 認識git結構 工作區&#xff1a;存放代碼的地方 暫存區&#xff1a;臨時存儲&#xff0c;將工作區的代碼…

構建RAG混合開發---PythonAI+JavaEE+Vue.js前端的實踐

7GB顯存如何部署bf16精度的DeepSeek-R1 70B大模型&#xff1f;-CSDN博客 服務容錯治理框架resilience4j&sentinel基礎應用---微服務的限流/熔斷/降級解決方案-CSDN博客 conda管理python環境-CSDN博客 快速搭建對象存儲服務 - Minio&#xff0c;并解決臨時地址暴露ip、短…

【Java ee初階】jvm(3)

一、雙親委派機制&#xff08;類加載機制中&#xff0c;最經常考到的問題&#xff09; 類加載的第一個環節中&#xff0c;根據類的全限定類名&#xff08;包名類名&#xff09;找到對應的.class文件的過程。 JVM中進行類加載的操作&#xff0c;需要以來內部的模塊“類加載器”…

wps excel將表格輸出pdf時所有列在一張紙上

記錄&#xff1a;wps excel將表格輸出pdf時所有列在一張紙上 1&#xff0c;調整縮放比例&#xff0c;或選擇將所有列打印在一頁 2&#xff0c;將表格的所有鋪滿到這套虛線

分布式微服務系統架構第134集:筆記1運維服務器經驗,高并發,大數據量系統

加群聯系作者vx&#xff1a;xiaoda0423 倉庫地址&#xff1a;https://webvueblog.github.io/JavaPlusDoc/ https://1024bat.cn/ https://github.com/webVueBlog/fastapi_plus https://webvueblog.github.io/JavaPlusDoc/ ? 一、查看端口是否被占用的常用命令 1?? lsof 命令&…

IS-IS 中間系統到中間系統

前言&#xff1a; 中間系統到中間系統IS-IS&#xff08;Intermediate System to Intermediate System&#xff09;屬于內部網關協議IGP&#xff08;Interior Gateway Protocol&#xff09;&#xff0c;用于自治系統內部 IS-IS也是一種鏈路狀態協議&#xff0c;使用最短路徑優先…

前端安全:XSS、CSRF 防御與最佳實踐

引言 隨著互聯網應用的普及&#xff0c;前端安全問題日益凸顯。作為開發者&#xff0c;了解并防范常見的安全威脅至關重要。本文將深入探討兩種最常見的前端安全威脅&#xff1a;跨站腳本攻擊&#xff08;XSS&#xff09;和跨站請求偽造&#xff08;CSRF&#xff09;&#xff…

uniapp 彈窗封裝(上、下、左、右、中五個方位)

無腦復制即可&#xff01;&#xff01;&#xff01; <template><view><viewv-if"mask"class"tui-drawer-mask":class"{ tui-drawer-mask_show: visible }":style"{ zIndex: maskZIndex }"tap"handleMaskClick&qu…

Axure制作可視化大屏動態滾動列表教程

在可視化大屏設計中&#xff0c;動態滾動列表是一種常見且實用的展示方式&#xff0c;能夠有效地展示大量信息。本文將詳細介紹如何使用Axure制作一個動態滾動的列表展示模塊。 一、準備工作 打開Axure軟件&#xff1a;確保你已經安裝并打開了Axure RP軟件。創建新項目&#x…

零基礎玩轉Apache Superset可視化部署

根據官方Quick Start Guide&#xff0c;你可以按照以下步驟進行部署&#xff1a; 1. 確認環境2. 獲取代碼3. 獲取官方最新代碼4. 啟動服務5. 訪問Superset Web界面6. 接入數據源 前提條件&#xff1a; dockerdocker compose 1. 確認環境 安裝Docker和Docker Compose 確保你…

服務器數據恢復—XFS文件系統分區消失的數據恢復案例

服務器數據恢復環境&故障&#xff1a; 服務器上有一組由raid卡組建的raid5磁盤陣列。上層安裝linux才做系統&#xff0c;采用XFS文件系統&#xff0c;劃分了3個分區。 管理員將服務器的操作系統重裝后&#xff0c;發現服務器上的分區發生了改變&#xff1a;一個分區消失&am…

2025/5/18

繼續研究一下大佬的RAG項目。開始我的碎碎念。 RAG可以分成兩部分&#xff1a;一個是問答&#xff0c;一個是數據處理。 問答是人提問&#xff0c;然后查數據庫&#xff0c;把查的東西用大模型組織成人話&#xff0c;回答人的提問。 數據處理是把當下知識庫里的東西&#xf…