C++高性能并行编程与优化 - 课件 - 17 由浅入深学习 map 容器由浅入深学习 map 容器 by 彭于斌( @archibate ) 我负责监督你鞋习 ! 我负责监督你鞋习 ! 本期看点: 用方括号 [ ] 取出 map 元素居然是错误的! 能不能在遍历的同时删除元素?安全吗? emplace , emplace_hint , try_emplace 的区别? 课程安排 1. vector 容器初体验 & 迭代器入门 (BV1qF411T7sd) 2 2. 你所不知道的 set 容器 & 迭代器分类 (BV1m34y157wb) 3. string , string_view , const char * 的爱恨纠葛 (BV1ja411M7Di) 4. 万能的 map 容器全家桶及其妙用举例 ( 本期 ) 5. 函子 functor 与 lambda 表达式知多少 6. 通过实战案例来学习 STL 算法库 7. C++ 标准输入输出流 & 字符串格式化 find(key); it == m.end()) { • return it->second; } else { • return defl; • } • } • 封装成函数方便使用: • auto val = map_get(m, “key”, “default”); • ss map 常用函数不同情况下的行为分析 类型 C++ 代码 key 已存在 key0 码力 | 90 页 | 8.76 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 13 C++ STL 容器全解之 vectorC++ STL 容器全解之 vector by 彭于斌( @archibate ) 往期录播: https://www.bilibili.com/video/BV1fa411r7zp 课程 PPT 和代码: https://github.com/parallel101/course C++ 标准库五大件:容器( container ) C++ 标准库五大件:迭代器( iterator 侯捷 STL 侯捷 STL vector 容器 vector 容器:构造函数 • vector 的功能是长度可变的数组,他里面的数据 存储在堆上。 • vector 是一个模板类,第一个模板参数是数组里 元素的类型。 • 例如,声明一个元素是 int 类型的动态数组 a : • vectora; vector 容器:构造函数和 size • vector 可以在构造时指定初始长度。 vector a(4); • 之后可以通过 a.size() 获得数组的长度。 • 比如右边这段代码会得到 4 。 • size_t size() const noexcept; vector 容器: operator[] • 要访问 vector 里的元素,只需用 [] 运算符 : • 例如 a[0] 访问第 0 个元素(人类的第一 个) • 例如 a[1] 访问第 1 个元素(人类的第二 0 码力 | 90 页 | 4.93 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 14 C++ 标准库系列课 - 你所不知道的 set 容器com/video/BV1qF411T7sd 课程安排 1. vector 容器初体验 & 迭代器入门 (BV1qF411T7sd) 2. 你所不知道的 set 容器 & 迭代器分类 ( 本期 ) 3. string , string_view , const char * 的爱恨纠葛 4. 万能的 map 容器全家桶及其妙用举例 5. 函子 functor 与 lambda 表达式知多少 6 标准输入输出流 & 字符串格式化 8. traits 技术,用户自定义迭代器与算法 9. allocator ,内存管理与对象生命周期 set 和 vector 的区别 • 都是能存储一连串数据的容器 。 • 区别 1 : set 会自动给其中的 元素从小到大排序,而 vector 会保持插入时的顺序。 • 区别 2 : set 会把重复的元素 去除,只保留一个,即去重。 • 区别 3 这样只会按字符串指针的地址去判断相等, 而不是所指向字符串的内容。 set 的排序:自定义排序函数 • set 作为模板类,其实有两 个模板参数: set• 第一个 T 是容器内元素的类 型,例如 int 或 string 等。 • 第二个 CompT 定义了你想 要的比较函子, set 内部会 调用这个函数来决定怎么排 序。 • 如果 CompT 不指定,默认 0 码力 | 83 页 | 10.23 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 02 现代 C++ 入门:RAII 内存管理课程大纲 • 分为前半段和后半段,前半段主要介绍现代 C++ ,后半段主要介绍并行编程与优化。 1.课程安排与开发环境搭建: cmake 与 git 入门 2.现代 C++ 入门:常用 STL 容器, RAII 内存管理 3.现代 C++ 进阶:模板元编程与函数式编程 4.编译器如何自动优化:从汇编角度看 C++ 5.C++11 起的多线程编程:从 mutex 到无锁并行 6.并行编程常用框架: ](https://git-scm.com/doc) - [GitHub 官方文档 ](https://docs.github.com/en) 古代: C 语言 近代: C++98 引入 STL 容器库 近现代: C++11 引入了 {} 初始化表达式 近现代: C++11 引入了 range-based for-loop 如果想使用 for_each 这个算法模板呢? 我知道可以用 accumulate 基于 C++17 标准,有时会谈到 C++20 作为扩展阅读。 C++ 有哪些面向对象思想? C++ 思想:封装 比如要表达一个数组,需要:起始地址指针 v ,数组大小 nv 将多个逻辑上相关的变量包装成一个类 因此 C++ 的 vector 将他俩打包起来,避免程序员犯错 封装:不变性 比如当我要设置数组大小为 4 时,不能只 nv = 4 还要重新分配数组内存,从而修改数组起始地址 v0 码力 | 96 页 | 16.28 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 06 TBB 开启的并行编程之旅课程大纲 • 分为前半段和后半段,前半段主要介绍现代 C++ ,后半段主要介绍并行编程与优化。 1.课程安排与开发环境搭建: cmake 与 git 入门 2.现代 C++ 入门:常用 STL 容器, RAII 内存管理 3.现代 C++ 进阶:模板元编程与函数式编程 4.编译器如何自动优化:从汇编角度看 C++ 5.C++11 起的多线程编程:从 mutex 到无锁并行 6.并行编程常用框架: 区别在于,一个任务不一定对应一个线程 ,如果任务数量超过 CPU 最大的线程数, 会由 TBB 在用户层负责调度任务运行在 多个预先分配好的线程,而不是由操作系 统负责调度线程运行在多个物理核心。 封装好了: parallel_invoke 更好的例子 第 1 章:并行循环 时间复杂度( time-efficiency )与工作量复杂度( work-efficiency ) • 在“小学二 是元素个数 并行映射 4 个线程,每人处理 2 个元素的映射,花了 2 秒 用电量: 4*2=8 度电 结论:并行映射的时间复杂度为 O(n/c) ,工作复杂度为 O(n) ,其中 c 是线程数量 封装好了: parallel_for 面向初学者: parallel_for 基于迭代器区间: parallel_for_each 二维区间上的 for 循环: blocked_range2d 三维区间上的0 码力 | 116 页 | 15.85 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 15 C++ 系列课:字符与字符串b 课程安排 1. vector 容器初体验 & 迭代器入门 (BV1qF411T7sd) 2. 你所不知道的 set 容器 & 迭代器分类 (BV1m34y157wb) 3. string , string_view , const char * 的爱恨纠葛 ( 本期 ) 4. 万能的 map 容器全家桶及其妙用举例 5. 函子 functor 就像你和同学随手“拉钩”定下的约定,这是 printf 约定俗成的。 • \ 就像正式合同,有法律效力的,这是 C 语言编译器规定好的。 C++ 字符串类 第 3 章 C 语言字符串操作繁琐 封装的 std::string 应运而生 封装的 std::string 应运而生 • string 可以从 const char * 隐式构造: • string s = “hello”; • string 具有 + 、 类型的,他们没有 + 运算 符。 • C++ 为了向前兼容,没办法改变 C 语言的这项规定,只能退而求其次,他另 外定义了一个 string 类,重载了 + 运算符,并告诉同学们:以后尽量用我这 个封装好的类,不要直接用 C 语言的 const char * 。 • 因此如果需要把两个字符串加在一起,就必须至少有一方是 string 才行。 • 可以用 string(“hello”) 这种形式包裹住每个字符串常量,这样就方便用0 码力 | 162 页 | 40.20 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 05 C++11 开始的多线程编程课程大纲 • 分为前半段和后半段,前半段主要介绍现代 C++ ,后半段主要介绍并行编程与优化。 1.课程安排与开发环境搭建: cmake 与 git 入门 2.现代 C++ 入门:常用 STL 容器, RAII 内存管理 3.现代 C++ 进阶:模板元编程与函数式编程 4.编译器如何自动优化:从汇编角度看 C++ 5.C++11 起的多线程编程:从 mutex 到无锁并行 6.并行编程常用框架: 5 章:数据结构 案例:多线程环境中使用 std::vector • 刚才说了, vector 不是多线程安全的容器 。 • 多个线程同时访问同一个 vector 会出现 数据竞争( data-race )现象。 封装一个线程安全的 vector • 因此,可以用一个类封装一下对 vector 的访问,使其访问都受到一个 mutex 的 保护。 • 然而却出错了:因为 size() defer_lock 做参数 , owns_lock() 判断等,同学们自己研究 。 只需一次性上锁,且符合 RAII 思想:访问者模式 Accessor 或者说 Viewer 模式,王鑫磊常用于设计 GPU 容器 OpenVDB 数据结构的访问,也是采用了 Accessor 的设计…… 并且还有 ConstAccessor 和 Accessor 两种,分别对应于读和 写 同学们可以想想看,如果这里的 m_mtx0 码力 | 79 页 | 14.11 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 12 从计算机组成原理看 C 语言指针太复杂了?没关系,用 C++ 的容器库 • 如果你觉得这样自己管理内存太麻烦了,那是 正常的。对于不精通 C 语言的小白程序员来 说,很容易就忘记释放内存了。 • 因此 C++ 提供了符合 RAII 思想的 vector 容器,他会在自己解构时自动释放内存。 • 小白程序员只需要保证自己总是在用 C++ 封 装好的容器而不是 C 语言指针,就可以基本 保证没有内存泄露。但是封装的太好了也有效 率问题,因此追求极致性能时还是会直接操作 原始的 C 语言指针。此外如果不理解容器的 底层原理也很容易犯错,因此我们还是要好好 学习 C 语言思想的。 C 语言特性:函数声明为 T [] 类型的参数,实际上是 T * 类型 • 如果函数参数类型形如 • func(int arr[]) • func(int arr[6]) • 那么他其实就等价于: • func(int* arr) 字符串实际上需要长度为 11 的字符数组 ! • 所以要把 str 声明为长度 11 的数组才行 。 C++ 的 string 容器 • 如果你搞不懂 C 语言硬核的 0 结尾字符 串,但还是害怕会发生内存越界的错误。 • 可以用 C++ 封装好的 string 容器和 cin 标准输入流。 cin 支持泛型, string 支持 自动扩容,符合 RAII 思想,可以避免小 白程序员犯错。0 码力 | 128 页 | 2.95 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - Zeno 中的现代 C++ 最佳实践 这里的解构函数也是多态的,他根据类型的不同 调用不同派生类的解构函数。 多态用于设计模式之“模板模式” • 这样之后如果有一个任务是要基于 eatFood 做文章,比如要重复 eatFood 两遍。 • 就可以封装到一个函数 eatTwice 里,这个函数只需接受他们共同的基类 IObject 作为参数,然后调 用 eatFood 这个虚函数来做事(而不是直接操作具体的猫和狗本身)。 • 这样只需要写一遍 思考:能不能把拷贝构造函数也作为虚函数? • 现在我们的需求有变,不是去对同一个对象调用两次 eatTwice ,而是先把对象复制一份 拷贝,然后对对象本身和他的拷贝都调用一次 eatFood 虚函数。 • 代码如下,这要怎么个封装法呢?你可能会想,是不是可以把拷贝构造函数也声明为虚函 数,这样就能实现了拷贝的多态?不行,因为 C++ 规定“构造函数不能是虚函数”。 模板函数?未免有些差强人意 • 索性把 eatTwice this 指针所指向的类型,也就是当前所在类的类型 。 • 宏的缺点是他不遵守命名空间的规则,宏的名 字是全局可见的,不符合 C++ 的高大尚封装思 想。 • 宏: IOBJECT_DEFINE_CLONE • 高大尚 C++ 封装: zeno::IObject::clone() 如何批量定义 clone 函数? • 另一种方法是定义一个 IObjectClone 模板 类。其模板参数是他的派生类0 码力 | 54 页 | 3.94 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 08 CUDA 开启的 GPU 编程https://github.com/parallel101/course 前置条件 • 学过 C/C++ 语言编程。 • 理解 malloc/free 之类的概念。 • 熟悉 STL 中的容器、函数模板等。 • 英伟达 GTX900 及以上显卡。 • CUDA 11 及以上。 • CMake 3.18 及以上。 我负责监督你学习 第 0 章: Hello, world! CMake 字。这里显示错误号为 77 ,具体名字是 cudaErrorIllegalAddress 。意思是我们访问了非法的地 址,和 CPU 上的 Segmentation Fault 差不多。 封装好了: helper_cuda.h • 其实 CUDA toolkit 安装时,会默认附带一系列案例代码, 这些案例中提供了一些非常有用的头文件和工具类,比如这 个文件: • /opt/cu https://developer.nvidia.com/blog/cuda-pro-tip-write-flexible-kernels-grid-stride-loops/ 第 4 章: C++ 封装 std::vector 的秘密:第二模板参数 • 你知道吗? std::vector 作为模板类,其实有两个模板参数: std::vector• 那为什么我们平时只用了 0 码力 | 142 页 | 13.52 MB | 1 年前3
共 24 条
- 1
- 2
- 3













