当前位置: 首页 > article >正文

第 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. 平台兼容性(不同编译器/架构)

相关文章:

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

使用更好的库 第八章核心知识点解析编译与测试建议总结优化原则重点内容&#xff1a;第一部分&#xff1a;多选题&#xff08;10题&#xff09;第二部分&#xff1a;设计题答案与解析多选题答案&#xff1a;设计题答案示例&#xff08;部分&#xff09;&#xff1a; 测试用例设…...

基于深度学习的图像超分辨率技术研究与实现

一、引言 在数字图像处理领域&#xff0c;图像超分辨率技术一直是一个备受关注的热点话题。随着人们对图像质量要求的不断提高&#xff0c;如何将低分辨率图像提升到高分辨率&#xff0c;同时保持图像的细节和清晰度&#xff0c;成为了一个极具挑战性的问题。传统的图像超分辨率…...

ubuntu22.04 ROS2humble 路径文件

ROS2humble 路径文件 /opt/ros/humble/include/opt/ros/humble/lib/opt/ros/humble/share 下载ros2之后会有下面的文件&#xff0c;在/opt/ros/humble下 /opt/ros/humble/include C/C 头文件&#xff08;.h, .hpp&#xff09; /opt/ros/humble/lib 作用: 存放 编译生成的二…...

OpenCV 图形API(或称G-API)

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 引言 OpenCV 图形API&#xff08;或称G-API&#xff09;是一个新的OpenCV模块&#xff0c;旨在使常规图像处理更快且更便携。通过引入一种新的基于图的执行…...

数据设计(范式、步骤)

文章目录 数据设计1.数据库设计的三大范式2、数据库设计的具体步骤 数据设计 1.数据库设计的三大范式 关系型数据库的三大范式&#xff0c;指导如何设计一个关系型数据库。 1NF&#xff1a; 关系表的每个字段&#xff0c;都应该是不可再分的&#xff0c;——保证原子性。 字…...

Linux命令大全:从入门到高效运维

适合人群&#xff1a;Linux新手 | 运维工程师 | 开发者 目录 一、Linux常用命令&#xff08;每天必用&#xff09; 1. 文件与目录操作 2. 文件内容查看与编辑 二、次常用命令&#xff08;按需使用&#xff09; 1. 系统管理与监控 2. 网络与通信 3. 权限与用户管理 三、…...

系统与网络安全------网络应用基础(3)

资料整理于网络资料、书本资料、AI&#xff0c;仅供个人学习参考。 路由器 路由器认识路由器工作原理基本配置直连路由远程管理路由器远程连接测试 路由器 认识路由器 负责在不同网络之间转发数据的设备 路由器决定到达目标的路径 路由器也为直连网络的主机充当”网关“角色…...

常用的测试用例

登录、添加、删除、查询模块是我们经常遇到的&#xff0c;这些模块的测试点该如何考虑 1)登录 ① 用户名和密码都符合要求(格式上的要求) ② 用户名和密码都不符合要求(格式上的要求) ③ 用户名符合要求&#xff0c;密码不符合要求(格式上的要求) ④ 密码符合要求&#xf…...

标准库中有uint32_t类型吗?

标准 C 库中有uint32_t类型。它定义在<stdint.h>头文件中&#xff0c;表示无符号 32 位整数类型。 #include <stdio.h> #include <stdint.h>int main() {uint32_t num 4294967295; // 32位无符号整数的最大值printf("The value of num is %u\n"…...

作业(7)

接口ip配置和区域划分&#xff1a; fw1&#xff1a; [fw1]interface GigabitEthernet 0/0/0 [fw1-GigabitEthernet0/0/0]service-manage all permit [fw1]firewall zone trust [fw1-zone-trust]add interface GigabitEthernet 1/0/0 [fw1]security-policy [fw1-policy-secu…...

kafka 报错消息太大解决方案 Broker: Message size too large

kafka-configs.sh --bootstrap-server localhost:9092 \ --alter --entity-type topics \ --entity-name sim_result_zy \ --add-config max.message.bytes10485880 学习营课程...

Burp Suite抓包实战:SQL注入漏洞挖掘

本文系统解析如何利用Burp Suite专业版开展SQL注入漏洞的定向挖掘&#xff0c;涵盖手动探测、自动化利用、WAF绕过等进阶技巧。通过电商、金融等行业的真实渗透案例&#xff0c;详解从流量拦截到漏洞利用的全链路方法论&#xff0c;实现单日最高挖掘23个高危注入点的实战成果。…...

open-cv的安装

python -m pip install numpy matplotlib opencv-python 【记得科学上网&#xff0c;不然太慢了】...

docker-compose自定义网络,解决docker-compose网段路由冲突

问题排查 先route一波查看一下路由表 容器路由19和堡垒机路由冲突 解决方案 更改docker网段更改docker生成容器的网段 > 基本操作 docker network ls &#xff1a;查看docker网络列表 docker network inspect <network id/name>&#xff1a;查看某个docker网络详情…...

数据库三级选择题(2)

C) 分布式数据库的事务管理包括恢复控制和并发控制&#xff0c;恢复控制一般采用的策略是基于两阶段提交协议 采用一定的计算方法定位数据的有 Ⅳ&#xff0e;散列&#xff08;哈希&#xff09;索引 下列提供逻辑独立性的是外模式/模式映像 UML所有活动有关判断的部分要用菱形表…...

【入门初级篇】报表基础操作与功能介绍

【入门初级篇】报表的基本操作与功能介绍 视频要点 &#xff08;1&#xff09;报表组件的创建 &#xff08;2&#xff09;指标组件的使用&#xff1a;一级、二级指标操作演示 &#xff08;3&#xff09;表格属性设置介绍 &#xff08;4&#xff09;图表属性设置介绍 &#xff0…...

GenBI 中如何引入 LLM 做意图路由,区分查数据还是闲聊

写在前面 生成式商业智能(Generative BI, GenBI)的魅力在于其能够理解用户的自然语言,并将复杂的数据查询和分析过程自动化。用户不再需要学习 SQL 或操作复杂的界面,只需像与同事交谈一样提出问题,就能获得数据洞察。然而,一个现实的挑战是:用户的输入并非总是明确的数…...

视频编码器的抉择:x264、x265、libaom、vvenc 对比测试实验

264、x265、libaom、vvenc 对比测试实验 测试机器配置&#xff1a;Apple M1 Pro -16G编码器版本&#xff08;选择自己编译&#xff09;&#xff1a;所有源码都是当前最新更新的状态&#xff0c;此外各类编码具体的编译过程可参考我的相关系列博客。 编码器GitHubx264git clon…...

【多媒体交互】Unity Kinect实现UI控件的点击

在Unity中&#xff0c;通过Kinect实现UI控件的点击功能&#xff0c;主要涉及手部追踪、坐标映射和手势检测三个核心环节。 实现步骤 初始化Kinect与关节追踪 使用KinectManager获取用户ID和手部关节点&#xff08;如JointType.HandLeft&#xff09;的坐标。 long userId _…...

vue将页面导出成word

方法一&#xff1a;使用 html-docx-js html-docx-js 是一个轻量级的库&#xff0c;可以将 HTML 转换为 Word 文档。 安装依赖 首先安装 html-docx-js&#xff1a; Bash深色版本 npm install html-docx-js --save创建导出逻辑 在 Vue 组件中实现导出功能的代码如下&#xff1…...

React 知识回顾(HOC、合成事件、Fiber)

HOC 嗯&#xff0c;用户问的是HOC是什么以及它能用来做什么。我需要先理解HOC的基本概念&#xff0c;然后整理它的用途。根据搜索结果&#xff0c;HOC是React中的高阶组件&#xff0c;用来复用逻辑。网页1提到HOC是一个函数&#xff0c;接收组件返回新组件&#xff0c;属于设计…...

hive相关面试题以及答案

什么是Hive&#xff1f;它的作用是什么&#xff1f; 答&#xff1a;Hive是一个建立在Hadoop之上的数据仓库工具&#xff0c;它提供了类似于SQL的查询语言HiveQL来操作存储在Hadoop中的数据。Hive的主要作用是让用户能够使用SQL语法来查询和分析大规模数据集。 Hive的架构是什么…...

Jmeter-负载测试

目录 一. 基础负载测试场景&#xff1a;固定并发用户数 1、线程组配置 2、HTTP请求配置 3、添加定时器 4、添加监听器 4.1 聚合报告 4.2 响应时间图 4.3 查看结果树 5、结果分析指标 二. 阶梯式加压场景&#xff08;逐步增加并发&#xff09; 1、插件安装 2、阶梯配…...

《深度剖析SQL数据类型转换:隐式与显式的奥秘》

在SQL的世界里&#xff0c;数据类型转换是一个基础且关键的操作&#xff0c;它贯穿于数据库开发、管理与数据分析的各个环节。数据类型转换分为隐式转换和显式转换&#xff0c;二者各有特点与应用场景&#xff0c;深刻理解它们对于编写高效、稳定的SQL代码至关重要。 一、数据…...

基于大模型的自发性气胸全方位预测与诊疗方案研究

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 二、大模型预测自发性气胸的原理及技术基础 2.1 大模型介绍 2.2 模型构建与训练数据 2.3 模型训练与优化 三、术前风险预测与准备 3.1 术前风险预测指标 3.2 基于预测的术前准备 3.3 手术方案与麻醉方案制定…...

经销商订货管理系统小程序PHP+uniapp

订货管理系统的行业变革势能 在实体商业与电商融合加速的2025年&#xff0c;订货管理系统已成为连锁品牌、商贸批发企业及工厂客户的核心数字化基建。面对经销商订货流程冗长、加盟商库存协同低效、批发贸易数据孤岛等行业痛点&#xff0c;新一代系统通过ThinkPHPUniapp技术架…...

性能测试理论基础-测试流程及方案设计要点

需求调研 因性能测试技术性和专业性要求比较高,通常需要性能测试人员参与需求调研和确认。 需求调研阶段,通常需要确认以下信息: 项目背景、测试范围、业务逻辑 & 数据流转(与开发确认)、系统架构、软硬件配置信息、 测试数据量(量级要一致)、外部依赖(第三方系统…...

TextGrad:案例

原文&#xff1a;Yuksekgonul, M., Bianchi, F., Boen, J. et al. Optimizing generative AI by backpropagating language model feedback. Nature 639, 609–616 (2025). https://doi.org/10.1038/s41586-025-08661-4 目录 Solution optimizationPrompt optimization for rea…...

kafka 4.x docker启动kafka4.0.0 docker-compose启动最新版kafka 如何使用docker容器启动最新版kafka

1. 镜像选择标签&#xff1a; https://hub.docker.com/r/bitnami/kafka/tags 2. 命令&#xff1a; docker pull bitnami/kafka:4.0.0 3. docker-compose.yml 启动kafka4.0.0&#xff1a; version: 3services:kafka:image: bitnami/kafka:4.0.0container_name: kafkaports:- &…...

Next.js 中间件鉴权绕过漏洞 (CVE-2025-29927) 复现利用与原理分析

免责声明 本文所述漏洞复现方法仅供安全研究及授权测试使用&#xff1b; 任何个人/组织须在合法合规前提下实施&#xff0c;严禁用于非法目的&#xff1b; 作者不对任何滥用行为及后果负责&#xff0c;如发现新漏洞请及时联系厂商并遵循漏洞披露规则。 漏洞原理 Next.js 是一个…...