第 8 章:使用更好的庫_《C++性能優化指南》_notes

使用更好的庫

      • 第八章核心知識點解析
      • 編譯與測試建議
      • 總結優化原則
      • 重點內容:
      • 第一部分:多選題(10題)
      • 第二部分:設計題
      • 答案與解析
        • 多選題答案:
        • 設計題答案示例(部分):
      • 測試用例設計原則:

第八章核心知識點解析

  1. 優化標準庫的使用
    知識點:選擇合適的數據結構、預分配內存、減少拷貝
#include <vector>
#include <chrono>
#include <iostream>// 測試vector的reserve對性能的影響
void test_vector_reserve() {const int N = 1000000;// 不預分配內存{std::vector<int> v;auto start = std::chrono::high_resolution_clock::now();for(int i=0; i<N; ++i) {v.push_back(i);}auto end = std::chrono::high_resolution_clock::now();std::cout << "Without reserve: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<< "μs\n";}// 預分配內存{std::vector<int> v;v.reserve(N);auto start = std::chrono::high_resolution_clock::now();for(int i=0; i<N; ++i) {v.push_back(i);}auto end = std::chrono::high_resolution_clock::now();std::cout << "With reserve: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<< "μs\n";}
}int main() {test_vector_reserve();return 0;
}

輸出示例

Without reserve: 5432μs
With reserve: 1276μs

關鍵點

  • reserve()預分配內存避免多次重新分配
  • 減少內存分配次數可提升3-4倍性能
  • 適用于vector、string等動態容器
  1. 優化現有庫
    知識點:添加批量處理接口
#include <vector>
#include <chrono>
#include <iostream>// 原始單元素處理接口
void process_element(std::vector<int>& vec, int value) {vec.push_back(value * 2);
}// 優化的批量處理接口
void process_batch(std::vector<int>& vec, const std::vector<int>& values) {vec.reserve(vec.size() + values.size());for(auto v : values) {vec.push_back(v * 2);}
}void test_batch_processing() {const int N = 10000;std::vector<int> input(N, 5);// 單次處理測試{std::vector<int> result;auto start = std::chrono::high_resolution_clock::now();for(auto v : input) {process_element(result, v);}auto end = std::chrono::high_resolution_clock::now();std::cout << "Single processing: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<< "μs\n";}// 批量處理測試{std::vector<int> result;auto start = std::chrono::high_resolution_clock::now();process_batch(result, input);auto end = std::chrono::high_resolution_clock::now();std::cout << "Batch processing: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<< "μs\n";}
}int main() {test_batch_processing();return 0;
}

輸出示例

Single processing: 856μs
Batch processing: 213μs

關鍵點

  • 批量處理減少函數調用開銷
  • 預分配內存進一步提升性能
  • 接口設計要考慮使用場景
  1. 設計高效庫
    知識點:扁平化調用鏈
#include <chrono>
#include <iostream>// 深層次調用鏈
class DeepCallChain {
public:void level3(int x) { data = x * 2; }void level2(int x) { level3(x); }void level1(int x) { level2(x); }int get() const { return data; }
private:int data;
};// 扁平化調用鏈
class FlatCallChain {
public:void process(int x) { data = x * 2; }int get() const { return data; }
private: int data;
};void test_call_chain() {const int N = 1000000;// 深層次調用{DeepCallChain obj;auto start = std::chrono::high_resolution_clock::now();for(int i=0; i<N; ++i) {obj.level1(i);}auto end = std::chrono::high_resolution_clock::now();std::cout << "Deep call chain: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<< "μs\n";}// 扁平調用{FlatCallChain obj;auto start = std::chrono::high_resolution_clock::now();for(int i=0; i<N; ++i) {obj.process(i);}auto end = std::chrono::high_resolution_clock::now();std::cout << "Flat call chain: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<< "μs\n";}
}int main() {test_call_chain();return 0;
}

輸出示例

Deep call chain: 2563μs
Flat call chain: 1245μs

關鍵點

  • 減少函數調用層級
  • 避免不必要的中間調用層
  • 扁平調用提升約50%性能
  1. 避免動態查找
    知識點:用直接訪問替代查找
#include <vector>
#include <algorithm>
#include <chrono>
#include <iostream>void test_access_method() {const int N = 100000;std::vector<int> data(N);std::iota(data.begin(), data.end(), 0);// 查找方式訪問{int sum = 0;auto start = std::chrono::high_resolution_clock::now();for(int i=0; i<N; ++i) {auto it = std::find(data.begin(), data.end(), i);if(it != data.end()) sum += *it;}auto end = std::chrono::high_resolution_clock::now();std::cout << "Find access: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<< "μs\n";}// 直接索引訪問{int sum = 0;auto start = std::chrono::high_resolution_clock::now();for(int i=0; i<N; ++i) {sum += data[i];}auto end = std::chrono::high_resolution_clock::now();std::cout << "Direct access: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<< "μs\n";}
}int main() {test_access_method();return 0;
}

輸出示例

Find access: 12563μs
Direct access: 256μs

關鍵點

  • 查找操作時間復雜度O(n)
  • 直接索引訪問復雜度O(1)
  • 性能差異可達50倍以上

編譯與測試建議

  1. 使用C++11及以上標準編譯:
g++ -std=c++11 -O2 example.cpp -o example
  1. 運行測試:
./example
  1. 典型優化效果對比:
  • 內存預分配可提升3-5倍性能
  • 批量接口比單次處理快2-4倍
  • 扁平調用鏈比深層次快1.5-2倍
  • 直接訪問比查找快10-50倍

總結優化原則

  1. 預分配原則:對已知大小的容器使用reserve()
  2. 批量處理:設計支持批量操作的接口
  3. 扁平設計:減少不必要的調用層次
  4. 直接訪問:用索引替代查找操作
  5. 內存重用:避免重復分配/釋放內存

重點內容:

  1. 標準庫性能特征與實現差異
  2. 自定義內存分配器的設計與應用
  3. 避免抽象懲罰的編程技巧
  4. 高效算法和數據結構的選擇
  5. 字符串處理優化策略
  6. 模板元編程的性能影響
  7. 異常處理的開銷控制
  8. 線程安全與性能平衡
  9. 緩存友好型數據結構設計
  10. 編譯器優化選項的合理使用

第一部分:多選題(10題)

  1. 關于標準庫容器的性能優化,以下哪些說法正確?
    A) vector的push_back時間復雜度是O(n)
    B) unordered_map的查找復雜度總是O(1)
    C) deque在中間插入元素的時間復雜度是O(n)
    D) list的迭代器失效規則與vector相同

  2. 下列哪些方法可以有效減少動態內存分配?
    A) 使用對象池模式
    B) 優先使用emplace_back代替push_back
    C) 為string預先調用reserve()
    D) 使用std::make_shared創建智能指針

  3. 關于字符串優化,哪些做法正確?
    A) 小字符串優化(SSO)可以避免堆分配
    B) 使用+=拼接比多次operator+更高效
    C) 移動語義可以完全消除字符串拷貝
    D) c_str()調用會觸發深拷貝

  4. 以下哪些算法選擇可能提升性能?
    A) 用std::sort替代冒泡排序
    B) 用std::lower_bound替代線性查找
    C) 用std::list替代std::vector存儲頻繁修改的序列
    D) 用std::array替代原始數組

  5. 關于內存分配器,正確的有:
    A) 自定義分配器可以減少鎖競爭
    B) std::allocator是線程安全的
    C) 內存池適合固定大小對象的分配
    D) 對齊分配對SIMD指令很重要

  6. 哪些模板使用可能影響性能?
    A) 深度嵌套的模板實例化
    B) 遞歸模板元編程
    C) 使用類型擦除的any類型
    D) 模板參數推導失敗

  7. 關于異常處理,正確的有:
    A) 異常規范影響代碼優化
    B) try塊會增加函數調用開銷
    C) noexcept聲明幫助編譯器優化
    D) 異常捕獲應盡量精確

  8. 緩存友好的設計包括:
    A) 使用緊湊數據結構
    B) 預取相鄰內存數據
    C) 隨機訪問鏈表節點
    D) 對齊內存訪問邊界

  9. 編譯器優化相關:
    A) -O3可能增加代碼體積
    B) LTO優化鏈接時代碼
    C) PGO需要訓練數據
    D) restrict關鍵字幫助別名分析

  10. 線程安全優化策略:
    A) 讀寫鎖減少競爭
    B) thread_local變量避免鎖
    C) 無鎖數據結構消除等待
    D) 原子操作總是比鎖高效


第二部分:設計題

設計題1:高效字符串拼接

// 要求:實現零拷貝的字符串拼接,支持鏈式調用
class StringBuilder {
public:StringBuilder& append(const std::string& s);std::string build();
private:// 設計存儲結構
};

設計題2:內存池分配器

// 實現固定塊大小的內存池,支持STL容器
template <typename T>
class PoolAllocator {
public:using value_type = T;// 必要接口實現
};

設計題3:類型擦除優化

// 設計替代虛函數調用的高效多態方案
template <typename T>
class FunctionWrapper {
public:template <typename F>FunctionWrapper(F&& f);void operator()() const;
private:// 存儲策略
};

設計題4:SIMD優化矩陣乘法

// 使用AVX指令優化4x4矩陣乘法
void matrix_multiply_avx(const float* a, const float* b, float* result);

設計題5:無鎖隊列

// 實現多生產者單消費者的無鎖隊列
template <typename T>
class LockFreeQueue {
public:void push(const T& value);bool pop(T& value);
private:// 設計節點結構和原子操作
};

答案與解析


多選題答案:
  1. BC
    C正確,deque中間插入O(n);B哈希表平均O(1)
    A錯,攤銷O(1);D錯,vector插入會使迭代器失效

  2. ABCD
    全部正確,B/D減少臨時對象,A/C預分配

  3. AB
    C錯,移動可能保留容量;D錯,c_str()不觸發拷貝

  4. AB
    C錯,vector更適合隨機訪問;D類型安全但性能相同

  5. ACD
    B錯,標準分配器線程安全但可能有鎖

  6. ABC
    D是編譯錯誤,不影響運行性能

  7. ACD
    B錯,try塊本身無運行時開銷

  8. ABD
    C鏈表導致緩存不命中

  9. ABCD
    全部正確

  10. ABC
    D錯,原子操作可能更慢


設計題答案示例(部分):

設計題1實現:

class StringBuilder {std::vector<std::reference_wrapper<const std::string>> parts;
public:StringBuilder& append(const std::string& s) {parts.emplace_back(s);return *this;}std::string build() const {size_t total = 0;for (const auto& s : parts) total += s.get().size();std::string result;result.reserve(total);for (const auto& s : parts) result += s.get();return result;}
};// 測試用例
int main() {StringBuilder sb;sb.append("Hello").append(" ").append("World");assert(sb.build() == "Hello World");
}

設計題2實現:

template <typename T>
class PoolAllocator {struct Block { Block* next; };Block* freeList = nullptr;public:T* allocate(size_t n) {if (n != 1 || !freeList) {return static_cast<T*>(::operator new(n * sizeof(T)));}auto head = freeList;freeList = freeList->next;return reinterpret_cast<T*>(head);}void deallocate(T* p, size_t n) {if (n != 1) {::operator delete(p);return;}auto block = reinterpret_cast<Block*>(p);block->next = freeList;freeList = block;}
};

剩下的設計題目, 后續補充


測試用例設計原則:

  1. 邊界測試(空容器、最大容量)
  2. 并發測試(多線程競爭)
  3. 性能對比(與標準實現比較)
  4. 內存泄漏檢測(Valgrind驗證)
  5. 平臺兼容性(不同編譯器/架構)

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

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

相關文章

RabbitMQ 學習整理1 - 基礎使用

項目代碼&#xff1a;RabbitMQDemo: 學習RabbitMQ的一些整理 基本概念 RabbitMQ是一種基于AMQP協議的消息隊列實現框架RabbitMQ可以用于在系統與系統之間或者微服務節點之間&#xff0c;進行消息緩存&#xff0c;消息廣播&#xff0c;消息分配以及限流消峰處理RabbitMQ-Serve…

React組件簡介

組件 在 React 中&#xff0c;組件&#xff08;Component&#xff09; 是 UI 的基本構建塊。可以把它理解為一個獨立的、可復用的 UI 單元&#xff0c;類似于函數&#xff0c;它接受輸入&#xff08;props&#xff09;&#xff0c;然后返回 React 元素來描述 UI。 組件的簡單…

Kafka消息序列化深度革命:構建高性能、高安全的自定義編碼體系

一、突破默認序列化的桎梏 1.1 原生序列化器的致命缺陷 Kafka默認提供的StringSerializer/ByteArraySerializer在復雜場景下暴露三大痛點&#xff1a; 類型安全黑洞&#xff1a;字節流缺乏元數據描述&#xff0c;消費端解析如履薄冰版本兼容困境&#xff1a;數據結構變更導致…

向量數據庫與傳統數據庫的差異

向量數據庫是一種專門設計用于高效存儲、管理和檢索**向量數據&#xff08;高維數值數組&#xff09;**的數據庫系統。它針對非結構化數據&#xff08;如圖像、文本、音頻&#xff09;的特征進行優化&#xff0c;通過將數據轉化為向量嵌入&#xff08;embeddings&#xff09;&a…

自動化框架的設計與實現

一、自動化測試框架 在大部分測試人員眼中只要沾上“框架”&#xff0c;就感覺非常神秘&#xff0c;非常遙遠。大家之所以覺得復雜&#xff0c;是因為落地運用起來很復雜&#xff1b;每個公司&#xff0c;每個業務及產品線的業務流程都不一樣&#xff0c;所以就導致了“自動化…

SpringBoot 3+ Lombok日志框架從logback改為Log4j2

r要將Spring Boot 3項目中的日志框架從Logback切換到Log4j2&#xff0c;并配置按日期滾動文件和控制臺輸出&#xff0c;請按照以下步驟操作&#xff1a; 步驟 1&#xff1a;排除Logback并添加Log4j2依賴 在pom.xml中修改依賴&#xff1a; <dependencies><!-- 排除默…

①、環境準備-主流技術(IPS/FW/主備-主主快速切換)

主流技術&(IPS/FW/主備-主主快速切換&#xff09; 一、RBM主備方案 RBM-FW-P 主配置內容介紹-注釋 remote-backup group 含義&#xff1a;定義了一個遠程備份組。這表明設備支持某種形式的遠程備份功能&#xff0c;用于在設備之間同步配置或數據。data-channel interface …

量化交通擁堵

指數&#xff1a; 基于嚴重擁堵里程比的指數和基于出行時間比的指數。 評價指標是飽和度&#xff08;VC比&#xff09;&#xff0c;它表示交通量與通行能力的比值。 飽和度可分為道路飽和度和路口飽和度。道路飽和度還會進一步分級&#xff0c;有四檔和六檔之分。 城市道路和…

PDF與Markdown的量子糾纏:一場由VLM導演的文檔界奇幻秀

緣起:當格式界的"泰坦尼克號"撞上"黑客帝國" 某個月黑風高的夜晚,在"二進制酒吧"的霓虹燈下: PDF(西裝革履地晃著威士忌): “我的每一頁都像瑞士手表般精密,連華爾街的禿鷲都為我傾倒!” Markdown(穿著帶洞的拖鞋): “得了吧老古董!…

【neo4j數據導出并在其他電腦導入】

停止服務 neo4j stop 導出 neo4j-admin database dump neo4j --to-path"C:\Users\12901\Downloads\test folder" 導入 將 .dump 文件放在一個目錄中 mkdir /root/dump-directory mv /root/neo4j.dump /root/dump-directory/ 使用包含 .dump 文件的目錄路徑作為 …

前端使用WPS WebOffice 做在線文檔預覽與編輯

先附上官網 WebOffice SDK 1、在下面這個地方找到jdk&#xff0c;然后下載 按照 2、只需要把jdk下載下來&#xff0c;放到項目中&#xff0c;然后引入到項目中就可以了&#xff0c;在wps 官網創建個應用&#xff0c;然后把appId放到代碼中就可以了&#xff0c;等待后端把回調…

跨語言微服務架構(Java、Python)——“API中臺”

文章目錄 一、引言二、系統架構概述2.1 統一單點登錄&#xff08;SSO&#xff09;與權限管理設計2.2 API中臺與數據中臺的融合2.3 跨語言適配器與 JWT 認證機制 三、技術細節與工具選型3.1 SSO 系統的選型與實現3.2 微服務架構與 API 中臺的實現3.3 跨語言適配器實現與技術難點…

DeepSeek V3-0324升級:開啟人機共創新紀元

一、技術平權&#xff1a;開源協議重構AI權力格局 DeepSeek V3選擇MIT協議開源6850億參數模型&#xff0c;本質上是一場針對技術壟斷的“數字起義”。這一決策的深層影響在于&#xff1a; 商業邏輯的重構 閉源AI公司依賴API收費的商業模式面臨根本性挑戰。當頂級模型能力可通過…

QOpenGLWidget視頻畫面上繪制矩形框

一、QPainter繪制 在QOpenGLWidget中可以繪制,并且和OpenGL的內容疊在一起。paintGL里面繪制完視頻后,解鎖資源,再用QPainter繪制矩形框。這種方式靈活性最好。 void VideoGLWidget::paintGL() {glClear(GL_COLOR_BUFFER_BIT);m_program.bind();//繪制視頻數據// 解綁VAOg…

3.3 Taylor公式

1.定義 1.1 taylor公式 1.2 麥克勞林公式 1.3 推論 1.4 拉格朗日余項和皮亞諾型余項 2. 例題 3.幾種特殊函數的麥克勞林展開

CEF 給交互函數, 添加控制臺是否顯示交互參數log開關

CEF 控制臺添加一函數,枚舉 注冊的供前端使用的CPP交互函數有哪些 CEF 多進程模式時,注入函數,獲得交互信息-CSDN博客 這兩篇文章,介紹了注入函數,在控制臺中顯示 各自提供的交互函數信息。 有些場景下,我們還需要更詳細的信息,比如想知道 彼此傳遞的參數, 如果每次調…

QTcpSocket多線程連接慢問題

20250325記錄 環境&#xff1a;Qt5.14.2 64位 msvc編譯 在多線程環境下&#xff0c;使用QTcpSocket實現客戶端&#xff0c;發現在少部分電腦上&#xff0c;連接時間過長&#xff0c;定時器檢查套接字狀態時&#xff0c;發現連接處于QAbstractSocket::ConnectingState狀態。 …

IntelliJ IDEA創建Maven工程

1、創建空工程 1&#xff09;創建 2&#xff09;配置JDK和Maven 2、創建Maven工程 3、Maven工程結構簡介 1&#xff09;目錄 pom.xml 2&#xff09;窗口 4、參考 08.IDEA配置本地Maven軟件_嗶哩嗶哩_bilibili

(UI自動化測試web端)第二篇:元素定位的方法_css定位之class選擇器

看代碼里的【find_element_by_css_selector( )】( )里的表達式怎么寫&#xff1f; 文章介紹了第二種寫法class選擇器。你要根據網頁中的實際情況來判斷自己到底要用哪一種方法來進行元素定位。每種方法都要多練習&#xff0c;全都熟了之后你在工作當中使用起來元素定位時&#…

加新題了,MySQL 8.0 OCP 認證考試 題庫更新

MySQL 8.0 OCP 認證考試 題庫更新 MySQL 8.0 Database Administrator 考試科目&#xff1a;1Z0-908 近期發現&#xff0c;MySQL OCP認證考試題庫發生變化&#xff0c;出現了很多新題&#xff0c;對此&#xff0c;CUUG專門收集整理了最新版本的MySQL考試原題&#xff0c;并會給…