### 有效使用 STL 的核心知识点 #### 一、选择容器时需谨慎 (Item1) - **要点概述**:选择合适的容器对于程序性能至关重要。不同容器的设计理念和内部实现机制各有侧重,例如`vector`适用于频繁访问但不频繁插入或删除元素的情况;而`list`则在频繁插入和删除元素时表现出色。 - **详细解释**: - **容器选择的影响因素**:考虑容器的使用场景、数据结构的特点以及容器操作的时间复杂度等因素。 - **容器特点举例**: - `vector`: 动态数组实现,支持随机访问,插入和删除操作效率低(特别是中间位置)。 - `list`: 双向链表实现,适合频繁插入和删除操作。 - `deque`: 双端队列,结合了数组和链表的优点,两端插入和删除效率高。 - **性能考量**:理解容器在内存中的布局方式,比如`vector`连续存储可以提高缓存效率。 #### 二、警惕“容器独立代码”的幻觉 (Item2) - **要点概述**:编写看似与容器无关的代码实际上可能隐藏着性能问题。 - **详细解释**: - **示例**:假设有一个函数用于处理容器内的元素,若该函数假定容器为`vector`,但实际上被用于`list`,则可能导致不必要的性能损失。 - **避免方法**:通过使用模板参数来明确指定容器类型,或者在函数设计时充分考虑到容器特性差异。 #### 三、确保容器中对象的复制既高效又正确 (Item3) - **要点概述**:在容器中存储自定义类型时,应确保这些类型的复制构造函数和赋值运算符足够高效且无误。 - **详细解释**: - **问题来源**:当容器需要复制或移动其内部元素时(如插入、删除等操作),如果自定义类型没有正确的拷贝构造函数和赋值运算符,可能导致内存泄漏或不一致状态。 - **解决方案**:为自定义类型提供深拷贝的拷贝构造函数和赋值运算符,确保对象能被正确复制和销毁。 #### 四、使用empty()替代检查size()是否为零 (Item4) - **要点概述**:相比检查`size()`是否为零,使用`empty()`方法更加简洁高效。 - **详细解释**: - **原因分析**:`empty()`通常比比较`size()`更快速,因为它只需判断一个标志位而非计算实际大小。 - **示例**:对于`vector<int> v; if(v.empty()) { /* ... */ }`来说,`empty()`会立即返回结果。 #### 五、优先选择范围成员函数而不是单个元素的操作 (Item5) - **要点概述**:当处理容器中的多个元素时,使用范围成员函数(如`std::copy`)通常更高效。 - **详细解释**: - **范围成员函数的优势**:这类函数可以一次处理整个范围的数据,减少代码量的同时提高执行效率。 - **实例**:使用`std::copy`复制容器中的所有元素相较于手动遍历复制更加简洁。 #### 六、警惕C++中最困扰人的解析问题 (Item6) - **要点概述**:C++中存在一种特定情况下非常令人困扰的语法解析问题,即函数声明可能被错误地解析为变量声明。 - **详细解释**: - **背景介绍**:这种问题主要发生在函数声明时缺少分号的情况。 - **解决办法**:在函数声明后添加分号或使用显式关键字如`auto`来避免歧义。 #### 七、使用指向新分配对象的指针时,请记得在容器销毁前释放指针 (Item7) - **要点概述**:当容器内包含指向动态分配的对象的指针时,必须在容器销毁之前释放这些指针。 - **详细解释**: - **问题描述**:如果不释放这些指针,将导致内存泄漏。 - **建议做法**:使用智能指针如`std::unique_ptr`或`std::shared_ptr`来管理这些对象,它们会在作用域结束时自动释放所管理的对象。 #### 八、切勿创建`auto_ptr`容器 (Item8) - **要点概述**:`auto_ptr`的特殊所有权转移机制使得在容器中使用它时极易出错。 - **详细解释**: - **问题原因**:`auto_ptr`在复制时会发生所有权转移,这会导致容器内部出现悬挂指针。 - **替代方案**:使用`std::unique_ptr`或`std::shared_ptr`等现代智能指针。 #### 九、谨慎选择容器的删除选项 (Item9) - **要点概述**:删除容器元素时应根据具体需求选择合适的方法。 - **详细解释**: - **删除选项**:包括`erase`、`remove`和`remove_if`等。 - **选择依据**:考虑是否需要保留容器大小不变、删除特定元素或删除满足条件的所有元素等因素。 #### 十、了解分配器的约定和限制 (Item10) - **要点概述**:掌握STL分配器的基本概念及其使用上的限制。 - **详细解释**: - **基本概念**:分配器负责管理容器所需的内存,通常由容器自动使用默认分配器。 - **注意事项**:使用自定义分配器时需注意其实现细节,确保其与容器兼容。 #### 十一、了解自定义分配器的合法用途 (Item11) - **要点概述**:了解如何正确使用自定义分配器来优化内存管理。 - **详细解释**: - **应用场景**:当需要精细控制内存分配策略时(如在嵌入式系统中)。 - **实现技巧**:设计自定义分配器时需确保其符合STL的接口规范,并考虑线程安全等问题。 #### 十二、对STL容器的线程安全性要有合理的期望 (Item12) - **要点概述**:了解STL容器在线程环境下的行为。 - **详细解释**: - **基本规则**:大多数STL容器和算法不是线程安全的,除非文档特别指出。 - **实践建议**:使用外部同步机制(如互斥锁)来保护共享数据。 #### 十三、优先使用`vector`和`string`而非动态分配数组 (Item13) - **要点概述**:相比于使用`new`和`delete`管理的动态数组,`vector`和`string`提供了更好的封装性和安全性。 - **详细解释**: - **优点**:`vector`和`string`自动管理内存,减少了内存泄漏的风险。 - **示例**:使用`vector<int>`代替手动管理的`int *`数组。 #### 十四、使用`reserve`避免不必要的重新分配 (Item14) - **要点概述**:通过预先调用`reserve`函数可以减少`vector`和`string`的重新分配次数。 - **详细解释**: - **工作原理**:`reserve`告诉容器预留足够的内存空间,从而避免多次小规模的内存分配。 - **应用场景**:在已知容器大小的情况下提前预留空间。 #### 十五、了解`string`实现的变体 (Item15) - **要点概述**:不同的编译器和库可能会有不同的`string`实现细节。 - **详细解释**: - **实现差异**:包括内存管理策略、容量调整机制等。 - **应对策略**:编写跨平台的代码时,关注这些差异并进行适当处理。 #### 十六、了解如何将`vector`和`string`数据传递给遗留API (Item16) - **要点概述**:当需要与旧版API交互时,了解如何将`vector`和`string`转换为适当的格式。 - **详细解释**: - **转换方法**:通过指针和长度信息将`vector`和`string`的数据暴露给遗留API。 - **注意事项**:确保转换后的数据在API使用期间保持有效。 #### 十七、使用“交换技巧”来减少额外容量 (Item17) - **要点概述**:通过`swap`操作来调整容器的容量。 - **详细解释**: - **工作原理**:利用`swap`函数交换两个容器的内容,其中一个容器事先被设置为所需大小。 - **优点**:比直接调用`resize`或`shrink_to_fit`更高效。 #### 十八、避免使用`vector<bool>` (Item18) - **要点概述**:由于`vector<bool>`特殊的实现方式,它可能带来意外的行为和性能问题。 - **详细解释**: - **问题原因**:`vector<bool>`使用位域存储元素,这可能导致迭代器失效等问题。 - **替代方案**:使用`std::bitset`或其他布尔数组实现。 #### 十九、理解等价性与相等性的区别 (Item19) - **要点概述**:在关联容器中,等价性与相等性是不同的概念。 - **详细解释**: - **概念区别**:等价性是指两个元素可以通过某种规则视为等同,而不必完全相等。 - **应用场景**:在`set`和`map`等关联容器中,等价性用于确定元素的唯一性。 #### 二十、为包含指针的关联容器指定比较类型 (Item20) - **要点概述**:当关联容器中存储的是指针时,需明确指定比较类型。 - **详细解释**: - **必要性**:指针本身仅表示内存地址,不能直接用于有意义的比较。 - **实现方法**:通过比较指针指向的对象内容来确定等价性或相等性。 #### 二十一、比较函数永远不应为相等值返回true (Item21) - **要点概述**:在关联容器中,比较函数不应为相等的元素返回`true`。 - **详细解释**: - **问题根源**:如果比较函数为相等的元素返回`true`,会导致容器行为异常。 - **解决方案**:确保比较函数遵循正确的逻辑,区分相等性和等价性。 #### 二十二、避免在`set`和`multiset`中就地修改键值 (Item22) - **要点概述**:在关联容器中直接修改键值可能导致元素丢失。 - **详细解释**: - **风险**:`set`和`multiset`内部使用红黑树组织元素,直接修改键值可能破坏树的结构。 - **规避策略**:先删除元素再插入更新后的版本。 #### 二十三、考虑使用排序后的`vector`替代关联容器 (Item23) - **要点概述**:在某些情况下,排序后的`vector`可以作为关联容器的有效替代品。 - **详细解释**: - **优势**:`vector`的访问速度更快,且内存使用更紧凑。 - **适用场景**:当元素数量相对较小且不会频繁变动时。 #### 二十四、仔细权衡`map::operator[]`和`map-insert`之间的选择 (Item24) - **要点概述**:根据具体情况选择使用`map::operator[]`还是`insert`操作。 - **详细解释**: - **选择依据**:`operator[]`在不存在键值时会自动插入元素,可能增加不必要的操作;而`insert`则需要显式检查键值是否存在。 - **示例**:在频繁查询不存在的键值时,使用`insert`配合`find`更为高效。 #### 二十五、熟悉非标准的哈希容器 (Item25) - **要点概述**:虽然STL未正式定义哈希容器,但仍可使用一些非标准实现。 - **详细解释**: - **实现方式**:通过第三方库(如Boost)或自定义实现。 - **优缺点**:哈希容器提供近似常数时间的查找性能,但其非标准性质可能导致跨平台问题。 #### 二十六、优先选择`iterator`而非`const_iterator`等其他迭代器类型 (Item26) - **要点概述**:在适用情况下,优先使用`iterator`。 - **详细解释**: - **原因分析**:`iterator`提供了更多的操作灵活性,如赋值等。 - **示例**:在需要修改容器内容的情况下,使用`iterator`更合适。 #### 二十七、使用`distance`和`advance`将容器的`const_iterator`转换为`iterator` (Item27) - **要点概述**:有时需要将`const_iterator`转换为具有更多操作权限的`iterator`。 - **详细解释**: - **转换方法**:通过`distance`获取两个迭代器间的距离,然后用`advance`移动`iterator`。 - **注意事项**:确保转换前后迭代器的有效性。 #### 二十八、理解反向迭代器的基迭代器使用方法 (Item28) - **要点概述**:掌握如何使用反向迭代器的基迭代器。 - **详细解释**: - **功能介绍**:反向迭代器的`base`成员可以返回其对应的正向迭代器。 - **应用场景**:当需要在正向顺序中处理逆序遍历的结果时。 #### 二十九、考虑使用`istreambuf_iterator`进行逐字符输入 (Item29) - **要点概述**:`istreambuf_iterator`提供了一种方便的方式逐字符读取输入流。 - **详细解释**: - **使用场景**:适合逐字符处理文本输入。 - **示例**:用于词法分析器或文本编辑器等场合。 #### 三十、确保目标范围足够大 (Item30) - **要点概述**:使用算法操作容器时,需确认目标容器有足够的空间容纳所有元素。 - **详细解释**: - **风险**:如果目标容器容量不足,可能导致数据丢失或未定义行为。 - **避免方法**:使用`reserve`预先预留空间或检查容器容量。 #### 三十一、熟悉排序选项 (Item31) - **要点概述**:了解STL提供的各种排序算法及其特点。 - **详细解释**: - **算法选择**:包括`sort`、`stable_sort`等,选择时需考虑稳定性、复杂度等因素。 - **应用示例**:根据数据特点选择最合适的排序算法。 #### 三十二、使用`remove`类算法后紧跟`erase` (Item32) - **要点概述**:使用`remove`或`remove_if`后,需使用`erase`移除满足条件的元素。 - **详细解释**: - **工作原理**:`remove`类算法仅将满足条件的元素移到容器末尾,不真正删除它们。 - **示例**:`std::vector<int> v = {1, 2, 3, 4}; std::remove(v.begin(), v.end(), 3); v.erase(std::remove(v.begin(), v.end(), 3), v.end());` 以上是《Effective STL》中的一些关键知识点总结,这些知识点对于理解和高效使用STL非常重要。希望对你有所帮助!
- 粉丝: 0
- 资源: 11
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- zfb-two-zfb-two
- 使用OpenGL实现Phong、Blinn-Phong模型
- Matlab界面面板版车牌识别系统设计实现[Matlab界面面板版].zip
- Matlab界面面板版车牌识别实现车牌定位[Matlab界面面板版].zip
- Matlab界面面板版车牌识别[Matlab界面面板版].zip
- GPT11111111111111111111
- 基于Matlab面板版的直线检测实现[Matlab面板版].zip
- CICD 持续集成与持续交付的部署gitlabgitlab-ce-17.1.6-ce.0.el9.x86-64.rpm
- GPT11111111111111111111
- unit2_eg.sql