STL六大组件 之 空间配置器

本文解析了SGI标准的空间配置器std::allocator及其效率问题,并深入探讨了SGI特殊的两级空间配置器的工作原理,包括一级配置器和二级配置器的具体实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

空间配置器存在的原因:

①频繁的申请和释放空间,就会频繁地调用malloc和free函数,函数调用时栈帧的开辟和回退,这些都是有开销的,就会降低运行的效率。

②频繁的申请和和释放空间,会造成内存碎片的问题。使得即使有足够的空间,也申请不到一个连续的空间。

 

SGI 标准的空间配置器:std::allocator, 它符合部分标准,但效率不佳,它只是把以下两个函数::operator new(只分配内存)和::operator delete(只回收内存)做了一层薄薄的包装而已(一般不使用)。

SGI 特殊的空间配置器:std::alloc 配置器定义在<memory>之中,SGI<memory>内包含两个文件:

 

1、#include<stl_alloc.h>   定义了一、二级配置器,负责内存空间的内配和释放,配置其名为alloc。

一级配置器:template<int inst>

class _malloc_alloc_template{…};

         其中:①allocate()直接使用malloc();deallocate()直接使用free()。

                    ②模拟C++的set_new_hander()以处理内存不足的情况。

二级配置器:template<bool threads,int inst>

class _default_alloc_template{…};

其中:①维护16个自由链表(free lists),负责维护16种小型区块的次配置能力。

                                     内存池(memory poll)以malloc()配置而得。

                                     如果内存不足,转调用第一级配置器(那儿有处理程序)。

②如果需求区块大于128bytes,就调用一级配置器。需求区块小于128bytes时,采用内存池整理方式,不再求助于一级配置器。

       对于是只开放一级配置器,还是同时开放二级配置器,取决于_USE_MALLOC是否被定义(如果定义:一级配置器;否则:二级配置器)

       在这两个配置器之上还有一层包装:simple_alloc ,使alloc具备标准接口。

SGI STL 容器的定义中默认使用二级空间配置器。

整个空间配置过程以一个例子说明:

       当vector需要扩容时,有三个步骤:1.重新配置空间,2.将原空间数据复制到新分配的空间,3. 释放原空间

在第一步重新配置空间中,就需要通过空间配置器去进行空间分配。

具体:

1、需配置空间大小n大于128字节,调用一级配置器进行分配。

2、需配置大小n小于128字节:

(1)在二级配置器维护的16个链表(free_list)中找到对接近n且大于n的区块链表,从这个区块中拔出首区块分配出去。

(2)如果free_list中没有合适区块了,则从内存池中分配空间给free_list(默认为20*k)

(3)如果内存池中也没有空间了,则从heap中malloc所需区块大小(以(2)中的默认大小为准)的2倍+附加量给内存池,在递归调用自己重新给free_list分配

(4)如果malloc失败,则从free_list上未使用且足够大的区块中找一块去配置所需区块,再去给用户分配空间

(5)如果free_list中也没有未使用的区块了,则调用一级配置器。因为以及配置器有out_of_memory机制,可以去处理分配失败问题,有机会释放其他的内存拿来此处用,如果失败,发出bad_alloc异常。

 

2、#include<stl_construct.h>    定义了construct() 和destroy(),都是全局函数,负责对象的构造和析构。

<think>首先,用户的问题是:“我想了解STL六大组件,可能是在学习C++标准模板库的基本构成。请问C++STL六大组件详解”。这是关于C++STL六大组件的详细解释。从系统级指令中,我需要遵循:-所有行内数学表达式使用$...$格式,但由于这是关于编程的,可能没有数学表达式,所以我可以忽略。-独立公式使用$$...$$格式并单独成段,同样可能不适用。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如:[^1]。用户可见层指令:-回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。-参考站内引用:引用[1]、[2]、[3]提供了相关信息。参考引用内容:-引用[1]:介绍了STL六大组件,包括容器算法迭代器仿函数适配器、分配器。并给出了fill和fill_n的例子。-引用[2]:详细解释了六大组件容器算法迭代器仿函数适配器、分配器,以及它们的交互关系。-引用[3]:提到标准函数对象如std::plus、std::minus、std::greater、std::less等,以及适配器。我的回答需要基于这些引用,但也要真实可靠。我会整合这些信息,提供一个清晰的解释。结构化回答:1.**介绍STL**:简要介绍STL(StandardTemplateLibrary)是什么。2.**六大组件详解**:逐一解释每个组件,使用引用中的信息。-容器(Containers)-算法(Algorithms)-迭代器(Iterators)-仿函数(Functors)-适配器(Adaptors)-分配器(Allocators)3.**交互关系**:解释这些组件如何协同工作。4.**代码示例**:如果需要,可以添加代码示例来演示,如引用[1]中的fill例子。5.**生成相关问题**:在末尾添加相关问题。在回答中,引用末尾添加引用标识。例如,如果我从引用[1]中引用了内容,就在段落末尾加[^1]。确保使用中文。生成相关问题:基于主题,生成几个相关问题。例如:1.STL容器有哪些常见类型?2.迭代器STL中的作用是什么?3.如何自定义仿函数?现在,构建回答大纲:-**开头**:介绍STL六大组件。-**主体**:详细解释每个组件。-容器:如vector、list等。-算法:如sort、copy等。-迭代器:遍历容器。-仿函数:函数对象。-适配器:如stack、queue。-分配器:内存管理。-**结尾**:总结交互关系,并添加相关问题。代码示例:可以包括引用[1]中的代码,但要用中文解释。</think>### C++ STL 六大组件详解 C++ 标准模板库(STL,Standard Template Library)是 C++ 语言中一个强大的泛型编程库,提供了一系列可复用的组件,用于高效处理数据结构和算法STL 的核心由六大组件构成,它们协同工作,实现了代码的高度可复用性和灵活性。下面我将逐一详细解释每个组件,结合示例和引用内容,帮助你逐步理解。 --- #### 1. **容器(Containers)** 容器STL 中的数据结构组件,用于存储和管理数据集合。它们以模板类(class template)的形式实现,支持多种数据类型和操作。常见的容器包括: - **序列容器**:如 `vector`(动态数组)、`list`(双向链表)、`deque`(双端队列)。 - **关联容器**:如 `set`(无序集合)、`map`(键值对映射)。 这些容器提供了统一的接口(如 `push_back()`, `insert()`, `erase()`),便于数据的增删改查。例如,`vector` 在内存中连续存储元素,适合随机访问;而 `list` 则适合频繁插入删除的场景[^1][^2]。 #### 2. **算法(Algorithms)** 算法STL 中的函数模板(function template),用于对容器执行操作,如排序、搜索、复制或修改元素。它们独立于容器类型,通过迭代器容器交互。常见算法包括: - `sort()`:对元素排序。 - `find()`:搜索指定元素。 - `copy()`:复制元素范围。 - `fill()`:填充容器元素(见下方代码示例)。 这些算法通常以泛型方式实现,适用于任何支持迭代器容器,保证了高效性和通用性[^1][^2]。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> v(5); // 创建一个包含5个元素的vector fill(v.begin(), v.end(), 1); // 使用fill算法将所有元素填充为1 for(int i : v) cout << i << " "; // 输出: 1 1 1 1 1 cout << endl; fill_n(v.begin(), 3, 2); // 使用fill_n算法填充前3个元素为2 for(int i : v) cout << i << " "; // 输出: 2 2 2 1 1 return 0; } ``` #### 3. **迭代器(Iterators)** 迭代器容器算法之间的“胶合剂”,扮演泛型指针的角色,用于遍历容器中的元素。STL 定义了多种迭代器类型: - **输入迭代器**:只读访问(如 `istream_iterator`)。 - **输出迭代器**:只写访问(如 `ostream_iterator`)。 - **前向迭代器**:单向遍历(如 `forward_list` 的迭代器)。 - **双向迭代器**:双向遍历(如 `list` 的迭代器)。 - **随机访问迭代器**:支持随机访问(如 `vector` 的迭代器)。 每个容器都提供专属迭代器(如 `v.begin()` 和 `v.end()`),确保算法能安全地操作数据[^1][^2]。 #### 4. **仿函数(Functors)** 仿函数(也称函数对象)是重载了 `operator()` 的类或类模板,行为类似函数,可作为算法的策略参数。它们分为: - **标准仿函数**:如 `std::plus<T>`(加法)、`std::greater<T>`(比较大小)、`std::less<T>`(比较小于)。 - **自定义仿函数**:用户可定义类来实现特定逻辑。 例如,`std::greater` 可配合 `sort` 算法实现降序排序: ```cpp sort(v.begin(), v.end(), greater<int>()); // 使用仿函数进行降序排序 ``` 仿函数比普通函数指针更灵活,支持状态保持和内联优化[^2][^3]。 #### 5. **适配器(Adaptors)** 适配器用于修饰容器仿函数迭代器的接口,使其适应不同需求。常见适配器包括: - **容器适配器**:如 `stack`(栈,基于 `deque` 实现)、`queue`(队列,基于 `deque` 实现)。 - **迭代器适配器**:如 `reverse_iterator`(反向遍历)。 - **函数适配器**:如 `bind2nd`(绑定函数参数)。 适配器通过封装底层组件,提供简化的接口。例如,`stack` 适配器隐藏了 `deque` 的细节,仅暴露 `push()`, `pop()`, `top()` 方法[^2][^3]。 #### 6. **分配器(Allocators)** 分配器负责内存的动态配置和管理,是容器底层的空间配置器。它以类模板形式实现,处理内存分配(`allocate()`)和释放(`deallocate()`)。默认使用 `std::allocator`,但用户可自定义分配器以优化特定场景(如内存池)。分配器与容器紧密集成,例如 `vector` 在构造时依赖分配器获取内存[^1][^2]。 --- #### 六大组件如何协同工作 STL 的核心设计是组件间的松耦合:算法通过迭代器访问容器元素,仿函数提供策略,适配器调整接口,分配器管理内存。这种设计实现了“高内聚低耦合”,例如: - 算法 `sort()` 使用迭代器遍历 `vector` 容器,并通过仿函数 `greater` 定义排序规则。 - 适配器 `stack` 基于 `deque` 容器实现,分配器处理内存分配。 这种协同机制让 STL 高效且易于扩展[^1][^2][^3]。 如果你有具体使用场景或代码问题,欢迎进一步提问! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值