STL源码剖析阅读
空间配置器
标准STL(包括GCC)提供
std::allocator
作为各容器的默认配置器,而不是书中所说的std::alloc
,且std::alloc
已经不存在。std::allocator
只使用new和delete操作,如书中所言是简单包装。旧版的
std::alloc
所持有的空间为全局所拥有,而新版的std::allocator
及其衍生物为各容器私有。为了解决空间利用率问题,引入了
std::pmr
空间,表示多态内存资源。空间中存在一个allocator
,为std::pmr::polymorphic_allocator
,即多态内存配置器。而空间中的容器例如std::pmr::vector
,即使用此配置器。因此,std::pmr::vector<std::string> v
即std::vector<std::string, std::pmr::polymorphic_allocator<std::string>> v
。std::pmr
空间中的容器不具有内存配置器传导性,即std::pmr::vector<std::pmr::string> v
则vector中string也使用此内存配置器,但是std::pmr::vector<std::string> v
中的string则使用默认配置器(std::allocator)。std::pmr
空间中的容器具有内存配置器所使用的资源(resource)传导性,例如
1 | std::array<std::byte, 200000> buf; |
则其中的string也会使用pool
来分配内存。
std::pmr
空间中资源(resource)具有三种,std::pmr::monotonic_buffer_resource
,std::pmr::unsynchronized_pool_resource
和std::pmr::synchronized_pool_resource
。std::pmr::monotonic_buffer_resource
只单调增长,虽然存在释放函数,但什么都不做。std::pmr::synchronized_pool_resource
是std::pmr::unsynchronized_pool_resource
的线程安全版本,使用std::lock_guard(std::mutex)
来保证。std::pmr::synchronized_pool_resource
内部存在两个成员,其一__pool_resource _M_impl
,是具体的实现,_TPools* _M_tpools
,是线程特殊内存池的链表。第一个内存池被所有线程共享。对于每一个内存池,都具有一个__pool_resource::_Pool
链表。每一个__pool_resource::_Pool
中,所有的block大小一致。当初始化_TPools
时会申请分级的__pool_resource::_Pool
。对于每一个__pool_resource::_Pool
对象,持有一个vector
(不同于std::vector),其内部按地址大小排列。vector内部元素是chunk,所有的chunk大小均一致为1024byte。每个chunk由开头的n个block和后面一个大小为n的bitset组成。bitset充当布隆过滤器的功能。_TPools
即一个多级内存池。(_TPools->_Pool->chunk->block
)此外,
__pool_resource _M_impl
中还存在一个vector,存储不会放在内存池中的块(过大的内存块)。初始化时,通过内存资源对象初始化
__pool_resource _M_impl
(其中的vector为std::pmr::vector
因此是通过内存资源初始化的),然后向M_impl
申请资源构造_TPools* _M_tpools
(通过构造临时构造器来构造)。当此std::pmr::synchronized_pool_resource
申请资源时,会通过分级得到合适的_Pool
,_Pool
分配无论是否存在空余都会传入内存资源对象(此对象_TPools* _M_tpools
持有),并向vector后加入chunk。POD类型存在unintialized_系列方法,例如unintialized_copy,表示向一块未初始化的区域上复制对象。
迭代器
容器需要设计迭代器的萃取(通过偏特化以对接STL算法接口)
容器需要设计迭代器
迭代器类型
输入迭代器
input iterator
输出迭代器
output iterator
前向迭代器
forward iterator
双向迭代器
bidirectional iterator
随机访问迭代器
random-access iterator
容器与算法
注意一下deque
仿函数与配接器
仿函数即结构体重载()运算符。
配接器分为三种
容器配接器(stack和queue,两者底层均为deque,只是隐藏了功能而已)
迭代器配接器(通过Output迭代器类型实现功能,例如把一般迭代器的复制操作转变为插入操作)
仿函数配接器(数学逻辑运算)
参考
《STL 源码剖析》STL 学习笔记 | Notes (landodo.github.io)
- Title: STL源码剖析阅读
- Author: Ethereal
- Created at: 2024-02-21 18:01:28
- Updated at: 2024-02-21 19:00:05
- Link: https://ethereal-o.github.io/2024/02/21/STL源码剖析阅读/
- License: This work is licensed under CC BY-NC-SA 4.0.