STL源码剖析阅读

Ethereal Lv4

空间配置器

  • 标准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> vstd::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
2
3
std::array<std::byte, 200000> buf;
std::pmr::monotonic_buffer_resource pool{buf.data(), buf.size()};
std::pmr::vector<std::pmr::string> coll{&pool};

则其中的string也会使用pool来分配内存。

  • std::pmr空间中资源(resource)具有三种,std::pmr::monotonic_buffer_resourcestd::pmr::unsynchronized_pool_resourcestd::pmr::synchronized_pool_resourcestd::pmr::monotonic_buffer_resource只单调增长,虽然存在释放函数,但什么都不做。std::pmr::synchronized_pool_resourcestd::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迭代器类型实现功能,例如把一般迭代器的复制操作转变为插入操作

    • 仿函数配接器(数学逻辑运算)

参考

gcc/libstdc++-v3/src/c++17/memory_resource.cc at ecfcc362b7f3f796c72f3525c4e3a6dd8ab3beac · gcc-mirror/gcc (github.com)

《STL 源码剖析》STL 学习笔记 | Notes (landodo.github.io)

《STL源码剖析》第8章配接器 - 知乎 (zhihu.com)

C++ STL 迭代器Iterator、五种迭代器类别_c++ iterator的种类-CSDN博客

  • 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.
 Comments