现代C++ 教程:高速上手C++11/14/17/20$(OBJECTS_C) $(LDFLAGS_COMMON) -o $(TARGET) clean: rm -rf *.o $(TARGET) 注意:Makefile 中的缩进是制表符而不是空格符,如果你直接复制这段代码到你的编辑器中, 制表符可能会被自动替换掉,请自行确保在 Makefile 中的缩进是由制表符完成的。 如果你还不知道 Makefile 的使用也没有关系,本教程中不会构建过于复杂的代码,简单的 显式禁用默认函数 在传统 C++ 中,如果程序员没有提供,编译器会默认为对象生成默认构造函数、复制构造、赋值 算符以及析构函数。另外,C++ 也为所有类定义了诸如 new delete 这样的运算符。当程序员有需要时, 可以重载这部分函数。 这就引发了一些需求:无法精确控制默认函数的生成行为。例如禁止类的拷贝时,必须将复制构造 函数与赋值算符声明为 private。尝试使用这些未定义的函数将导致编译或链接错误,则是一种非常不 之为可调用类型。而这种类型,便是通过 std::function 引入的。 C++11 std::function 是一种通用、多态的函数封装,它的实例可以对任何可以调用的目标实体进 行存储、复制和调用操作,它也是对 C++ 中现有的可调用实体的一种类型安全的包裹(相对来说,函数 指针的调用不是类型安全的),换句话说,就是函数的容器。当我们有了函数的容器之后便能够更加方便 的将函数、函数指针作为对象进行处理。例如:0 码力 | 83 页 | 2.42 MB | 1 年前3
Hello 算法 1.1.0 C++ 版据结构可 以动态地添加或删除元素,但它们的容量是固定的。如果数据量超出了预分配的大小,就需要创建一个新的 第 3 章 数据结构 hello‑algo.com 65 更大的数组,并将旧数组的内容复制到新数组中。 Q:在构建栈(队列)的时候,未指定它的大小,为什么它们是“静态数据结构”呢? 在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 在复杂的系统环境中,程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。因此在 大多数编程语言中,数组的长度是不可变的。 如果我们希望扩容数组,则需重新建立一个更大的数组,然后把原数组元素依次复制到新数组。这是一个 ?(?) 的操作,在数组很大的情况下非常耗时。代码如下所示: // === File: array.cpp === /* 扩展数组长度 */ int *extend(int *nums, int size, int enlarge) { // 初始化一个扩展长度后的数组 int *res = new int[size + enlarge]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size; i++) { res[i] = nums[i]; } // 释放内存 delete[] nums; // 返回扩展后的新数组0 码力 | 379 页 | 18.47 MB | 1 年前3
Hello 算法 1.2.0 简体中文 C++ 版以动态地添加或删除元素,但它们的容量是固定的。如果数据量超出了预分配的大小,就需要创建一个新的 第 3 章 数据结构 www.hello‑algo.com 65 更大的数组,并将旧数组的内容复制到新数组中。 Q:在构建栈(队列)的时候,未指定它的大小,为什么它们是“静态数据结构”呢? 在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 在复杂的系统环境中,程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。因此在 大多数编程语言中,数组的长度是不可变的。 如果我们希望扩容数组,则需重新建立一个更大的数组,然后把原数组元素依次复制到新数组。这是一个 ?(?) 的操作,在数组很大的情况下非常耗时。代码如下所示: // === File: array.cpp === /* 扩展数组长度 */ int *extend(int *nums, int size, int enlarge) { // 初始化一个扩展长度后的数组 int *res = new int[size + enlarge]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size; i++) { res[i] = nums[i]; } // 释放内存 delete[] nums; // 返回扩展后的新数组0 码力 | 379 页 | 18.48 MB | 10 月前3
Hello 算法 1.0.0 C++版据结构可 以动态地添加或删除元素,但它们的容量是固定的。如果数据量超出了预分配的大小,就需要创建一个新的 第 3 章 数据结构 hello‑algo.com 65 更大的数组,并将旧数组的内容复制到新数组中。 Q:在构建栈(队列)的时候,未指定它的大小,为什么它们是“静态数据结构”呢? 在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 在复杂的系统环境中,程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。因此在 大多数编程语言中,数组的长度是不可变的。 如果我们希望扩容数组,则需重新建立一个更大的数组,然后把原数组元素依次复制到新数组。这是一个 ?(?) 的操作,在数组很大的情况下非常耗时。代码如下所示: // === File: array.cpp === /* 扩展数组长度 */ int *extend(int *nums, int size, int enlarge) { // 初始化一个扩展长度后的数组 int *res = new int[size + enlarge]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size; i++) { res[i] = nums[i]; } // 释放内存 delete[] nums; // 返回扩展后的新数组0 码力 | 378 页 | 17.59 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - 10 从稀疏数据结构到量化数据类型位运算 >> 对负数的处理 signed 类型的 >> n 会把最高位复制 n 次。 因为补码的特性,这导致负数 >> 的结果仍是负 数。 这样就实现了和 Python 一样的始终向下取整除 法。 >> 2 = unsigned 类型的位运算 >> 不一样 而 unsigned 类型的 >> n 会不会复制最高位, 只是单纯的位移,这会导致负数的符号位单独被位 移,补码失效,造成结果不对。0 码力 | 102 页 | 9.50 MB | 1 年前3
Hello 算法 1.0.0b1 C++版nums, int size, int enlarge) { // 初始化一个扩展长度后的数组 int* res = new int[size + enlarge]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size; i++) { res[i] = nums[i]; } // 释放内存 delete[] nums; // 返回扩展后的新数组 newCapacity = capacity() * extendRatio; int* tmp = nums; nums = new int[newCapacity]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size(); i++) { nums[i] = tmp[i]; } // 释放内存 delete[] tmp; numsCapacity nex = getInOrderNext(cur->right); int tmp = nex->val; // 递归删除结点 nex remove(nex->val); // 将 nex 的值复制给 cur cur->val = tmp; } return cur; } /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ TreeNode* getInOrderNext(TreeNode*0 码力 | 187 页 | 14.71 MB | 1 年前3
Hello 算法 1.0.0b2 C++版nums, int size, int enlarge) { // 初始化一个扩展长度后的数组 int* res = new int[size + enlarge]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size; i++) { res[i] = nums[i]; } // 释放内存 delete[] nums; // 返回扩展后的新数组 newCapacity = capacity() * extendRatio; int* tmp = nums; nums = new int[newCapacity]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size(); i++) { nums[i] = tmp[i]; } // 释放内存 delete[] tmp; numsCapacity nex = getInOrderNext(cur->right); int tmp = nex->val; // 递归删除结点 nex remove(nex->val); // 将 nex 的值复制给 cur cur->val = tmp; } return cur; } /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ TreeNode* getInOrderNext(TreeNode*0 码力 | 197 页 | 15.72 MB | 1 年前3
Hello 算法 1.0.0b5 C++版*nums, int size, int enlarge) { // 初始化一个扩展长度后的数组 int *res = new int[size + enlarge]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size; i++) { res[i] = nums[i]; } // 释放内存 delete[] nums; // 返回扩展后的新数组 连续空间存储是一把双刃剑,其存在以下缺点。 ‧ 插入与删除效率低: 当数组中元素较多时,插入与删除操作需要移动大量的元素。 ‧ 长度不可变: 数组在初始化后长度就固定了,扩容数组需要将所有数据复制到新数组,开销很大。 ‧ 空间浪费: 如果数组分配的大小超过了实际所需,那么多余的空间就被浪费了。 4.1.3 数组典型应用 数组是一种基础且常见的数据结构,既频繁应用在各类算法之中,也可用于实现各种复杂数据结构。 newCapacity = capacity() * extendRatio; int *tmp = nums; nums = new int[newCapacity]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size(); i++) { nums[i] = tmp[i]; } // 释放内存 delete[] tmp; numsCapacity0 码力 | 377 页 | 30.69 MB | 1 年前3
Hello 算法 1.0.0b4 C++版*nums, int size, int enlarge) { // 初始化一个扩展长度后的数组 int *res = new int[size + enlarge]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size; i++) { res[i] = nums[i]; } // 释放内存 delete[] nums; // 返回扩展后的新数组 newCapacity = capacity() * extendRatio; int *tmp = nums; nums = new int[newCapacity]; // 将原数组中的所有元素复制到新数组 for (int i = 0; i < size(); i++) { nums[i] = tmp[i]; } // 释放内存 delete[] tmp; numsCapacity right); } 合并方法 merge() 代码中的难点包括: ‧ 在阅读代码时,需要特别注意各个变量的含义。nums 的待合并区间为 [left, right] ,但由于 tmp 仅 复制了 nums 该区间的元素,因此 tmp 对应区间为 [0, right - left] 。 ‧ 在比较 tmp[i] 和 tmp[j] 的大小时,还需考虑子数组遍历完成后的索引越界问题,即 i >0 码力 | 343 页 | 27.39 MB | 1 年前3
C++高性能并行编程与优化 - 课件 - Zeno 中的现代 C++ 最佳实践 小知识: shared_ptr 如何深拷贝? 浅拷贝: 深拷贝: 思考:能不能把拷贝构造函数也作为虚函数? • 现在我们的需求有变,不是去对同一个对象调用两次 eatTwice ,而是先把对象复制一份 拷贝,然后对对象本身和他的拷贝都调用一次 eatFood 虚函数。 • 代码如下,这要怎么个封装法呢?你可能会想,是不是可以把拷贝构造函数也声明为虚函 数,这样就能实现了拷贝的多态?不行,因为0 码力 | 54 页 | 3.94 MB | 1 年前3
共 12 条
- 1
- 2













