深入理解STL空间分配器(一)

目录

1.概述

2. STL的几种空间分配器介绍

3. new_allocator

3.1 allocate的实现

3.2 deallocate的实现

3.3 其中几个宏的定义

3.4 _M_max_size的实现

4. malloc_allocator


1.概述

STL的空间分配器(allocator)定义于命名空间std内,主要为STL容器提供内存的分配和释放、对象的构造和析构的统一管理。空间分配器的实现细节,对于容器来说完全透明,容器不需关注内存分配和回收的策略细节如何。

STL allocator需实现如下4个标准接口:

pointer allocate(size_type __n, const void*);     //内存分配
void deallocate(pointer __p, size_type __n);     //内存释放 
void construct(pointer __p, const _Tp& __val);    //构造
void destroy(pointer __p);              //析构

2. STL的几种空间分配器介绍

  • __new_allocator:C++标准中定义的分配器,仅对operator new和operator delete做简单封装;

  • malloc_allocator:C++标准中定义的分配器,仅对std::malloc和std::free做简单封装;

  • __mt_alloc:一种支持多线程的空间配置器(亦可单线程),可分配2的幂次方大小的内存块,该配置器可灵活调整,性能高(stl手册描述,个人未实测);

  • bitmap_allocator:一种使用位图来区分内存是否分配的配置器;

  • __pool_alloc:带有单锁内存池的器,即侯捷于《STL源码剖析》中介绍的SGI-STL空间配置器;

  • debug_allocator:该空间分配器主要用于调试,可包裹其他allocator,于用户层申请的内存大小的基础上扩容部分,附带调试信息;

  • throw_allocator:具有日志记录和异常生成控制的分配器;

补充说明:operator new和std::malloc都是仅申请内存,申请的内存不做初始化,但其仍存在如下区别:

  • operator new 可由用户重载,调用new关键字时将自动调用重载的operator new函数,而std::malloc不能重载;

  • operator new 有异常机制,在内存申请失败时会抛出异常,std::malloc申请失败只会返回NULL;

  • std::malloc 可和realloc结合使用,调整内存申请大小,operator new无类似的操作;

3. new_allocator

template<typename _Tp>
class __new_allocator
{
public:/* 重定义了几种类型别名 */typedef _Tp        value_type;typedef std::size_t     size_type;typedef std::ptrdiff_t  difference_type;
#if __cplusplus <= 201703Ltypedef _Tp*       pointer;typedef const _Tp* const_pointer;typedef _Tp&       reference;typedef const _Tp& const_reference;template<typename _Tp1>struct rebind{ typedef __new_allocator<_Tp1> other; };
#endif/* 以下几个构造和析构函数,没有做特别实现 */_GLIBCXX20_CONSTEXPR__new_allocator() _GLIBCXX_USE_NOEXCEPT { }_GLIBCXX20_CONSTEXPR__new_allocator(const __new_allocator&) _GLIBCXX_USE_NOEXCEPT { }template<typename _Tp1>_GLIBCXX20_CONSTEXPR__new_allocator(const __new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { }#if __cplusplus <= 201703L~__new_allocator() _GLIBCXX_USE_NOEXCEPT { }/* 取参数地址 */pointeraddress(reference __x) const _GLIBCXX_NOEXCEPT{ return std::__addressof(__x); }const_pointeraddress(const_reference __x) const _GLIBCXX_NOEXCEPT{ return std::__addressof(__x); }
#endif_GLIBCXX_NODISCARD _Tp*allocate(size_type __n, const void* = static_cast<const void*>(0));voiddeallocate(_Tp* __p, size_type __n __attribute__ ((__unused__)));#if __cplusplus <= 201703Lsize_typemax_size() const _GLIBCXX_USE_NOEXCEPT{ return _M_max_size(); }#if __cplusplus >= 201103L/* C++11新特性,采用std::forward将参数完美转发,保留其右值属性 *  调用placement new,在已分配好的内存上构造对象,形参为std::forward转发的参数*/template<typename _Up, typename... _Args>voidconstruct(_Up* __p, _Args&&... __args)noexcept(std::is_nothrow_constructible<_Up, _Args...>::value){ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }/* 显示调用析构函数 */template<typename _Up>voiddestroy(_Up* __p)noexcept(std::is_nothrow_destructible<_Up>::value){ __p->~_Up(); }
#else/* 调用placement new,在已分配好的内存上构造对象 */voidconstruct(pointer __p, const _Tp& __val){ ::new((void *)__p) _Tp(__val); }/* 显示调用析构函数 */voiddestroy(pointer __p) { __p->~_Tp(); }
#endif
#endif // ! C++20/* 以下重载了“=”和“!=”运算符,不做特殊实现 */template<typename _Up>friend _GLIBCXX20_CONSTEXPR booloperator==(const __new_allocator&, const __new_allocator<_Up>&)_GLIBCXX_NOTHROW{ return true; }#if __cpp_impl_three_way_comparison < 201907Ltemplate<typename _Up>friend _GLIBCXX20_CONSTEXPR booloperator!=(const __new_allocator&, const __new_allocator<_Up>&)_GLIBCXX_NOTHROW{ return false; }
#endifprivate:_GLIBCXX_CONSTEXPR size_type_M_max_size() const _GLIBCXX_USE_NOEXCEPT;
}

以上代码裁剪了源码的部分实现,加入个人注释理解。空间配置器的重点在于内存的分配和释放,对象的构造和析构,new_allocator对此仅用operator new、operator delete、placement new做简单封装。

上述代码中rebind 的定义是stl中的一个特点,所有的空间配置器都实现了类似如下的定义

template<typename _Tp1>
struct rebind
{ typedef __new_allocator<_Tp1> other; };

其作用在于,实现对不同类型采用同一内存分配策略的需求。

空间配置器作为容器的模板参数,容器只知其形参名而不知其具体的内存配置策略如何,当容器需要对另一类型采用同样的内存配置策略时,此时就可以采用rebind,获取到其所需另一类型的,符合同一内存分配策略的空间配置器

std::allcoator<T>::rebind<U>::other 等价于std::allcoator<U>。

3.1 allocate的实现

template<typename _Tp1>
struct rebind
{ typedef __new_allocator<_Tp1> other; };_GLIBCXX_NODISCARD _Tp*
allocate(size_type __n, const void* = static_cast<const void*>(0))
{
#if __cplusplus >= 201103L/* 静态断言,编译期间检查类型大小 */static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types");
#endif/* GCC 提供的分支预测 */if (__builtin_expect(__n > this->_M_max_size(), false)){if (__n > (std::size_t(-1) / sizeof(_Tp)))std::__throw_bad_array_new_length();std::__throw_bad_alloc();}#if __cpp_aligned_new/* 当类型对齐后的大小大于系统默认内存对齐大小,采用 * void* operator new ( std::size_t count, std::align_val_t al) 作为内存申请的接口*/if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__){std::align_val_t __al = std::align_val_t(alignof(_Tp));return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp),__al));}
#endifreturn static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
}
  • __builtin_expect(exp, x) 是GCC的一个内建函数,用于分支预测,提高性能(处理if else分支时,前面分支的汇编指令会先装载,后面分支的指令需要通过JMP指令才能访问,JMP访问比前者更耗时间,大量的JMP访问会有性能开销,因此,采用分支预测,CPU提前装载执行概率更高的指令,提高性能)。
      __builtin_expect(exp, x)期望的表达式exp==x,当x=0时,if分支执行的可能性小,否则else分支执行的可能性小。函数的范围值为exp。

  • STDCPP_DEFAULT_NEW_ALIGNMENT 是 operator new 操作对齐值的阈值,超过这个值,operator new将无法保证分配的内存满足对齐要求,此时可用 void* operator new ( std::size_t count, std::align_val_t al) 作为内存申请的接口,该接口为C++17实现。接口将强行使用指定的参数作为内存对齐的大小分配内存。

  • alignof(_Tp)运算符用于计算类型的内存对齐大小。std::align_val_t 为枚举类型,定义如:enum class align_val_t: size_t {}; 域化枚举,并指定类型为size_t。

3.2 deallocate的实现

void
deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__)))
{
#if __cpp_sized_deallocation
# define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp)
#else
# define _GLIBCXX_SIZED_DEALLOC(p, n) (p)
#endif#if __cpp_aligned_newif (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__){_GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n),std::align_val_t(alignof(_Tp)));return;}
#endif_GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n));
}

3.3 其中几个宏的定义

#if __has_builtin(__builtin_operator_new) >= 201802L
# define _GLIBCXX_OPERATOR_NEW __builtin_operator_new
# define _GLIBCXX_OPERATOR_DELETE __builtin_operator_delete
#else
# define _GLIBCXX_OPERATOR_NEW ::operator new
# define _GLIBCXX_OPERATOR_DELETE ::operator delete
#endif

3.4 _M_max_size的实现

_GLIBCXX_CONSTEXPR size_type
_M_max_size() const _GLIBCXX_USE_NOEXCEPT
{
#if __PTRDIFF_MAX__ < __SIZE_MAX__return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
#elsereturn std::size_t(-1) / sizeof(_Tp);
#endif
}

4. malloc_allocator

malloc_allocator的实现与new allocator实现类似,区别在于调用的接口不同,malloc_allocator封装的接口为std::malloc和std::free。此空间配置器不做源码分析。

本章节所分析的源码基于gcc-master。

原文地址:https://www.cnblogs.com/hjx168/p/16057220.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/611216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Super关键字

与this关键字用法相同&#xff0c;但super关键字指的是父类的对象 我们常用super.来调用父类对象的属性或者方法 super关键字出来调用父亲的属性还可以调用父亲的方法&#xff0c;方式也是super. super() super()表示调用父类的无参构造 super(参数列表)表示调用父类的有参…

Java中的网络编程

文章目录 网络基础知识IP 地址端口协议 Java 中网络编程InetAddress&#xff08;静态类&#xff09;UDP 通信原理UDP 发送数据步骤UDP 接收数据步骤UDP 发送接收案例 TCP 通信原理TCP 发送数据步骤TCP 接收数据步骤TCP 发送接收案例 网络基础知识 概述&#xff1a;在网络通信协…

认识Linux指令之与时间相关的指令

01.date命令 date 指定格式显示时间&#xff1a; date %Y:%m:%d date 用法&#xff1a;date [OPTION]... [FORMAT] 1.在显示方面 在显示方面&#xff0c;使用者可以设定欲显示的格式&#xff0c;格式设定为一个加号后接数个标记&#xff0c;其中常用的标记列表如下 %H : …

RT-Thread: 线程创建及应用

说明&#xff1a;这里记录 RT-Thread 的具体创建过程&#xff0c;相当于线程创建的一个模式&#xff0c;具体线程相关的信息没做介绍&#xff0c; RT-Thread 的官方文档里面已经有详细介绍&#xff0c;如有需要请移步官网。 官网链接&#xff1a;https://www.rt-thread.org/do…

【揭秘APT攻击】——内网渗透实战攻略,带你领略网络安全的绝密世界!

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 介绍 什么是内网&#xff1f; 什么是内网渗透&#xff1f; 内网渗透的目的&#xff1a; 内网…

天鹅目标检测数据集VOC格式280张

天鹅&#xff0c;一种优雅而美丽的鸟类&#xff0c;以其洁白的羽毛、优美的身姿和动人的歌声而闻名。 天鹅属于鸟纲、鸭科&#xff0c;是一种大型水禽。它们的羽毛通常是白色、黑色或灰色&#xff0c;非常光滑且富有光泽。天鹅的头部和颈部非常细长&#xff0c;呈现出优雅的曲…

面试题-手撕NMS(非极大值抑制)

非极大值抑制&#xff08;Non-Maximum Suppression&#xff0c;NMS&#xff09;是一种常用于目标检测和计算机视觉中的算法&#xff0c;用于去除重叠的边界框&#xff0c;保留最可能是真实目标的边界框。 其核心就是对一组检测框&#xff0c;找出其中属于同一个类别且分数最高…

烟雾识别摄像机

烟雾识别摄像机是一种具有智能识别功能的监控设备&#xff0c;它能够通过图像识别技术检测和识别烟雾&#xff0c;提供实时监测和报警功能。这种摄像机通常应用于各种场所&#xff0c;如工厂、仓库、办公楼、酒店等&#xff0c;起到了重要的安全监测作用。 烟雾识别摄像机的工作…

C++入门【26-C++ Null 指针】

在变量声明的时候&#xff0c;如果没有确切的地址可以赋值&#xff0c;为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。 NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序&#xff1a; 实例 #include <iostream> using…

新手练习项目 4:简易2048游戏的实现(C++)

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#xff09; 目录 一、效果图二、代码&#xff08;带注释&#xff09;三、说明 一、效果图 二、代码&#xff08;带…

光伏方案设计有什么注意点?

光伏方案设计是实现光伏发电系统高效运行的关键环节。在进行光伏方案设计时&#xff0c;有几个重要的注意点需要特别关注。 首先&#xff0c;要充分考虑地理位置和气候条件。不同地区的日照时数、太阳辐射强度和日照角度都有所不同&#xff0c;这些因素直接影响光伏发电系统的发…

FS【1】:SSP

文章目录 前言1. Abstract2. Introduction2.1. Motivation2.1.1. Few-shot Segmentation (FSS) Task2.1.2. Few-shot Segmentation (FSS) Problem 2.2. Contribution 3. Methods3.1. Motivation3.2. Overview of the architecture4.3. Self-support Prototype4.4. Adaptive Sel…

C++:多态究竟是什么?为何能成为面向对象的重要手段之一?

C&#xff1a;多态究竟是什么&#xff1f;为何能成为面向对象的重要手段之一&#xff1f; 前言一、多态的概念二、多态的定义及实现2.1 多态的构成条件2. 2 虚函数2.3 虚函数的重写2.3.1 虚函数重写的例外1&#xff1a;协变(基类与派生类虚函数返回值类型不同)2.3.2 虚函数重写…

领域驱动模型之各层实体严格分层处理

为什么要分层处理呢&#xff1f; 在领域驱动模型中&#xff0c;分为应用层&#xff08;application&#xff09;、领域层&#xff08;domain&#xff09;、基础设施层&#xff08;infrastructure&#xff09;。各层只能处理和访问自己所属层的 entity 或者 dto 对象&#xff0…

基于ssm的理财通的设计与实现+jsp论文

摘 要 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以&#xff0c;对理财信息管理的提升&#xff0c…

针对大规模服务日志敏感信息的长效治理实践

文章目录 1 背景2 目标与措施3 实施3.1 脱敏工具类3.2 JSON脱敏3.3 APT自动脱敏3.3.1 本地缓存问题3.3.2 JDK序列化问题 3.4 弃用方案 4 规划5 总结 1 背景 近年来&#xff0c;国家采取了多项重要举措来加强个人数据保护&#xff0c;包括实施《中华人民共和国网络安全法》和《…

TypeError: Cannot read properties of undefined (reading ‘namespace‘)

项目场景&#xff1a; 背景&#xff1a; Java 项目中使用 activi 流程引擎&#xff0c; 创建一个带有排他网关的 申请审核流程&#xff0c; 创建之后 查看 流程图出现 如下所示的 错误信息。 前端页面 不显示 任何 流程图信息。 问题描述 问题&#xff1a; 例如&#xff1…

鸿蒙系列--属性动画

一、定义 当组件的通用属性发生改变时而产生的属性渐变效果 说明&#xff1a; 当组件的通用属性发生改变时&#xff0c;组件状态由初始状态逐渐变为结束状态的过程中&#xff0c;会创建多个连续的中间状态&#xff0c;逐帧播放后&#xff0c;就会形成动画 二、创建 给组件(如…

SCS模型(径流曲线法)概述

目录 1.介绍&#xff1a;2.计算公式&#xff1a;参考文献&#xff1a;小结&#xff1a; 1.介绍&#xff1a; SCS模型&#xff08;径流曲线法&#xff09;是由美国农业部水土保持局(Soil Conservation Service) 基于经验提出&#xff0c;最初用于预测在农业用地小型流域降雨所累…

【算法每日一练]-dfs (保姆级教程 篇9) #俄罗斯方块 #ABC Puzzle #lnc的工资

目录 今日知识点&#xff1a; 二维图形的状态压缩&#xff0c;存下所有的合法状态然后暴力遍历 dfs的优化剪枝 二项式定理 俄罗斯方块 ABC Puzzle lnc的工资 俄罗斯方块 322D 题意&#xff1a;在4*4方格中分别给出3个俄罗斯方块&#xff0c;问是否可以经过旋转&#xf…