SGISTL源码探究-空间配置器

c++实现一个简单的空间配置器allocator c++实现一个简单的空间配置器allocator       c++中内存分配和对象构造是分开来的,内存的分配类似malloc函数在内存空间开辟一段空间,但是里面不保存任何数据。对象的构造相当于给这段空间复制。       这么做的理由有两点:       在预先分配的内存中构造对象很浪费,可能创建从不使用的对象,当实际使用预先分配的对象时,被使用的对象往往又必须重新 阅读详情

前言

该系列的博客主要是看SGISTL3.0源码,并参考了一些相关的博客还有《STL源码剖析》一书得到的心得及一些自己的理解整理而成,如有错误请指出,谢谢。

allocator

引入

事实上,我们在学习C++的时候,接触到空间配置器应该就是allocator,它用于申请一块未初始化的空间,这是因为new会执行两个动作,首先申请空间,其次调用其构造函数。但是如果有些空间根本就不会用到,那么调用构造函数初始化会浪费效率。而allocator解决了这个问题,即分配/释放内存时只调用malloc和free,而将构造/析构动作分开。(其实new和free一般也是调用这两个函数,但是又额外增加了初始化以及析构动作)

代码实例
#include <iostream>
using namespace std;
#include <memory>
#include <vector>

int main()
{
    //定义一个配置器对象
    allocator<vector<int> > alloc;
    //使用该配置器分配3个未初始化的vector<int>
    vector<int>* p = alloc.allocate(3);
    vector<int>* q = p;
    for(int i = 0; i < 3; i++)
    {
        //调用vector<int>的构造函数
        alloc.construct(q++, 1, i*10);
        //输出(此时相当于是二维数组p[3][])
        cout << p[i][0] << endl;
    }
    //循环调用析构函数
    while(q != p)
    {
        alloc.destroy(--q);
    }
    //释放分配的空间
    alloc.deallocate(p, 3);
    return 0;
}

编译链接g++ -std=c++11 allocator.cpp
以上便是allocator空间配置器最简单的使用。从中我们可以看出要使用allocator配置器,需要包含头文件<memory>。以及有如下几个基本的接口:

  1. allocate(size_t n):用于分配n个对象
  2. construct(T* p, args):用于构造类型为T*的指针p指向的对象,args是构造函数的参数
  3. destroy(T* p):即对类型为T*的指针p指向的对象调用对应的析构函数
  4. deallocate(T* p, size_t n):用于释放内存,需要注意指针p指向的一定要是分配时的起始地址,否则可能造成未定义的结果。
深入源码

下面我们就来看看allocator的那些接口是如何实现的,首先我们还是先从construct()和destroy()入手,因为allocate()稍微复杂一些,涉及了两级配置器,第一级用于申请超过128bytes的空间,第二级用于申请小空间,采用了内存池技术。

  • construct()
template <class T1, class T2>
inline void construct(T1* p, const T2& value)
{
  new (p) T1(value);
}

代码其实就一行new (p) T1(value),但是new不是会分配新的内存吗,你可能会有这样的疑惑。其实这里的new跟你认识的operator new不太一样,而是placement new,它重载了operator new,用于在一个已经分配好的内存中(堆/栈)构造一个新的对象。这也是一种显示调用构造/析构函数的一种方法,另一种直接在函数前加作用域。那么这样我相信你就可以理解了。(ps:使用placement new需要包含头文件<new.h>)

  • destroy
    destroy其实有多个版本,针对了不同的情况。

    1. 传入一个指针
    2. 传入两个迭代器,有trivial destructor
    3. 传入两个迭代器,有non-trivial destructor
    4. 迭代器是char *和wchar *

    情况一:

    template<class T>
    inline void destroy(T* pointer)
    {
    pointer->~T();
    }

    这种情况没什么好说的
    情况二和情况三的共同部分:
    在具体到情况二和三之前,有一些公共的内部接口

    template <class ForwardIterator>
    inline void destroy(ForwardIterator first, ForwardIterator last)
    {
    __destroy(first, last, value_type(first));
    }
    
    template <class ForwardIterator, class T>
    inline void __destroy(ForwardIterator first, ForwardIterator last, T*)
    {
    typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
    __destroy_aux(first, last, trivial_destructor());
    }

    首先是接受两个迭代器作为范围的destroy,它内部调用__destroy,value_type()用于获取迭代器所指对象的类型,运用traits技法实现,至于具体如何实,在分析迭代器时会讲解。而在__destroy中,内部调用__destroy_aux,最后一个参数是trivial_destructor(),其实这是一个typedef,跟__type_traits有关,也放在后面讲解,现在你只用知道它的作用是判断是否有trivial destructor就行了。

    情况二:

    template <class ForwardIterator>
    inline void __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)
    {
    for(; first < last; ++first)
    {
      destroy(&*first);
    }
    }

    这个情况是针对non-trivial destructor,意思也就是在[first,last)范围内,调用情况一的函数,即依次调用析构函数。看第三个参数__false_type,很明显,它是一个对象,嗯….从中你可能会看出点什么。
    情况三:

    template <class ForwardIterator>
    inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type){}

    这里唯一可以让我们关注的就只有__true_type了,跟情况二结合不难发现,通过trivial_destructor()的返回值是__true_type还是__false_type,而选择不同的情况。而trivial_destructor其实是个typedef定义的,根据不同的情况,分别为__true_type和__false_type,比如基础类型int之类的,肯定就typedef成__true_type了。__true_type和__false_type是两个空类。trivial_destructor()即构造一个对象。
    情况四:

    inline void destroy(char *, char *){}
    inline void destroy(wchar_t *, wchar_t *){}

    如你所见,这两种类型根本不需要做什么。

分了这几种情况,主要是在效率方面上的考虑,有一些对象本来的析构函数就属于没什么用的,调用这种析构函数只会浪费时间,特别是在范围析构的时候。

小结

在本小节中,我们主要了解了allocator的简单的用法以及construct和destroy函数针对不同的情况采取的最具效率的做法。前面已经提到过分为两级配置器,所以allocate和deallocate对应的也应该有两种,一种是第一级配置器,另一种是第二级配置器。在下节中,我们将看看第一级配置器是如何分配以及释放内存的。

机器人中的数值优化(十三)——QP二次规划 本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考,主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等,本系列文章篇数较多,不定期更新,上半部分介绍无约束优化,下半部分介绍带约束的优化,中间会穿插一些路径规划方面的应用实例 阅读详情

相关推荐

在Mac上搭建本地AI工作流:Dify与DeepSeek的完美结合

本文介绍了在Mac上搭建本地AI工作流的方法,结合Dify平台和DeepSeek模型。Dify是一个开源的大语言模型应用开发平台,支持可视化AI应用开发。部署步骤包括:1)安装Homebrew和Docker;2)克隆Dify代码库;3)配置环境变量并启动服务。同时,使用Ollama工具本地部署DeepSeek模型,将其集成到Dify中创建聊天助手。通过配置模型接口和新建应用,用户可以在本地环境中实现AI对话功能。这种方案既保证了数据隐私,又提供了灵活的AI应用开发能力。

Linda的自动化测试之旅 1535

SGISTL源码探究-vector容器(上)

前言vector容器应该算是最常用的容器之一了,它是序列式容器的一种,即元素可被排序。vector被称为动态数组,可以随着元素的加入,内部的大小自行扩充。可能你对vector的机制有所耳闻,比如每次扩充时,扩充当前容量的2倍等。接下来,我们就进入到它的源码来看看vector是如何实现的。我们将它分为四部分进行分析,vector的迭代器,vector的内存分配及构造,vector的内存控制以及一些常用

Move_now的博客 810

SAP WM模块事务码(TCODE)大全

OL07 Data transfer stor.bins LDK34->RLPLA 仓储位LDK34 ->RLPLA

matinal 當冬夜漸暖 。公众号:matinal 5846

SGI STL的二级空间配置器的源码剖析并内存池的实现源码剖析

2019年8月16日23:41:07 剖析源码的好处:学习优秀的编程规范 和 设计理念;以及剖析源码的能力。 内存池的实现 内容如下: SGI STL二级空间配置器源码 Nginx内存池源码剖析 这两种内存池的实现和应用场景都是不一样的。 为什么要内存池呢? 答:C语言的库函数malloc和free C++的new和delete(其底层的内存管理上依旧是malloc和free)。但是在应用场...

孤傲小二~阿沐的博客 800

深入解析docx4j:从Word到PDF的高保真转换实战

本文深入解析了如何使用纯Java开源库docx4j实现Word到PDF的高保真转换。针对中文环境,重点讲解了字体映射原理、Linux服务器字体部署方案,并提供了完整的代码示例和配置方法。同时,文章涵盖了表格、图片处理、性能优化及生产环境部署指南,帮助Java开发者构建稳定、可控的文档转换服务。

weixin_29237635的博客 672

【无人机设计与控制】基于PID控制的四旋翼无人机系统Matlab仿真

本文设计并仿真了基于PID控制的四旋翼无人机系统。首先,建立了四旋翼无人机的数学模型,涵盖了无人机的动力学和控制系统。通过PID控制器对四旋翼的姿态和位置进行控制,以实现其稳定飞行。使用MATLAB/Simulink对该系统进行仿真,验证了PID控制算法在四旋翼控制中的有效性。仿真结果表明,PID控制能够较好地调节四旋翼的飞行姿态,并有效抑制外部干扰,使得无人机能够保持平稳飞行。

2401_84610415的博客 1804

SGI STL二级空间配置器源码剖析(1)

之前大概写过SGI STL相关的东西,讲了讲空间配置器的原理,这一系列就剖析一下源码。在C++STL里空间配置器做的事情就是分离了对象内存的开辟,释放,对象构造,析构我们看SGI STL的实现还是找到vector看他push_back实现会发现他的构造析构都是定义的全局的函数模板SGI STL两个allocator的实现还是一级的是malloc和free,和C++STL基本无差,不过二级的用内存池的方式实现就复杂了进到空间配置器源码看看。

oorik的博客 597

在PyCharm中配置使用Anaconda环境

在PyCharm中配置使用Anaconda环境一、步骤1.Anaconda2.PyCharm总结 一、步骤 1.Anaconda 如未安装Anaconda可至其官网下载,学习使用个人版就可以了。 下载地址:https://www.anaconda.com/products/individual 1、打开Anaconda Navigator,点击Environments可以看到anaconda中已经有了默认的“base”环境,其中包含了大多数我们会用到的包,在PyCharm中可以直接使用该环境,而无需自行下载

TuckX的博客 19万+

SGI STL二级空间配置器内存池的源码移植项目

2019年8月21日23:39:54 首先SGI STL二级空间配置器内存池的源码解剖可以 详见我的博客: SGI STL二级空间配置器内存池的源码解剖 源码移植实现空间配置器是用模板实现的,因此代码只能放在头文件里面了。(不可以把类和方法声明写在头文件里面,然后在源文件里面去实现模板方法)而且这里也是需要考虑一下:多线程环境下的线程安全问题。毕竟空间配置器是给容器使用的,而容器产生的对象是 很有...

孤傲小二~阿沐的博客 509

LS-DYNA壳单元冲击仿真中的5个关键设置:以方管碰撞为例(含沙漏控制参数)

本文以方管碰撞为例,深入解析了LS-DYNA壳单元冲击仿真中的五个关键设置。重点探讨了沙漏控制参数(如IHQ=4)的选择逻辑、自接触算法优化、能量监控方法、材料模型(MAT_24)的真实应力-应变曲线与应变率效应设置,以及单元公式的选取。这些核心设置共同决定了仿真的精度与效率,是确保方管冲击仿真结果可靠性的基石。

salt的博客 625

Git下载与安装

一、Git下载 二、Git安装

欢迎订阅我的“JAVA全栈开发笔记(全)”专栏,价格优惠,仅需19.9元。 6万+

STL之空间配置器源码解析

配置器(allocator) 配置器:负责空间配置与管理,从实现的角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的模板类。 空间配置器意义:整个 STL 的操作对象(包含的所有数值)都存放在容器之内,空间配置器就是用来帮助这些容器管理(动态开辟,回收)内存空间,使其可以动态存放内容。 SGI STL 空间配置器的结构 SGI STL 的配置器,其名称是 alloc 而不是 allocator,而且不接受任何参数。allocator 只是基层内存配置/释放行为(::operator::new 和

angry_youth的博客 318

STM32实现简单的智能电梯控制

上述代码实现了一个简单的智能电梯控制器。电梯的状态包括IDLE(停止)、UP(向上移动)和DOWN(向下移动)三种状态。通过向上和向下按钮的按下,可以控制电梯移动到指定的楼层。在主循环中,不断读取当前楼层的按钮状态,并根据电梯状态决定执行的动作。具体的楼层数量和按钮的GPIO引脚可以根据实际情况进行调整。要实现简单的智能电梯控制,我们可以使用STM32微控制器来实现。

2401_85258012的博客 336

深度剖析SGI STL二级空间配置器内存池源码

文章目录一、SGI STL二级空间配置器重要成员解读1. 二级空间配置器内存池的结构2. 两个重要的函数(1) _S_round_up(2)_S_freelist_index3. 内存池allocate分配过程 一、SGI STL二级空间配置器重要成员解读 SGI STL包含了一级空间配置器和二级空间配置器 其中一级空间配置器allocator采用malloc和free来管理内存,和C++标准库中提供的allocator是一样的 但其二级空间配置器allocator采用了基于freelist自由链表原理的

长期更新自学笔记 1803

aac编码源码

aac编码源码,可以拿去试试。

springboot+vue基于协同过滤算法的音乐推荐系统源码.zip

springboot+vue基于协同过滤算法的音乐推荐系统,本音乐网站的开发主要利用 VUE 框架开发前台和后台,后端接口用 Spring Boot + MyBatis 来实现,数据库使用的是 MySQL。springboot+vue基于协同过滤算法的音乐推荐系统,本音乐网站的开发主要利用 VUE 框架开发前台和后台,后端接口用 Spring Boot + MyBatis 来实现,数据库使用的是 MySQL。springboot+vue基于协同过滤算法的音乐推荐系统,本音乐网站的开发主要利用 VUE 框架开发前台和后台,后端接口用 Spring Boot + MyBatis 来实现,数据库使用的是 MySQL。springboot+vue基于协同过滤算法的音乐推荐系统,本音乐网站的开发主要利用 VUE 框架开发前台和后台,后端接口用 Spring Boot + MyBatis 来实现,数据库使用的是 MySQL。springboot+vue基于协同过滤算法的音乐推荐系统,本音乐网站的开发主要利用 VUE 框架开发前台和后台,后端接口用 Spring Boot +

SGI STL二级空间配置器源码移植

SGI STL二级空间配置器源码移植 【SGI STL源码刨析】 malloc_alloc源码移植 // malloc_alloc.h文件 #ifndef MALLOC_ALLOC_H #define MALLOC_ALLOC_H #include <malloc.h> // 封装了malloc和free操作,可以设置OOM释放内存的回调函数 template <int __i...

weixin_43604792的博客 219

C_PAT:中国大学MOOC-翁恺-C语言程序设计习题集

C_PATThis repo is my practice for 中国大学MOOC-翁恺-C语言程序设计习题集 on PAT.The website is .idtitle02-0整数四则运算(10)02-1厘米换算英尺英寸(15)02-2然后是几点(15)02-3逆序的三位数(10)02-4BCD解密(10)03-0超速判断(10)03-1三天打鱼两天晒网(15)03-2用天平找小球(10)03-312-24小时制(15)03-4成绩转换(15)04-0求符合给定条件的整数集(15)04-1水仙花数(20)04-2打印九九口诀表(15)04-3统计素数并求和(20)04-4猜数字游戏(15)05-0求序列前N项和(15)05-1约分最简分式(15)05-2念数字(15)05-3求a的连续和(15)06

SGISTL源码探究-默认使用的配置器

前言在上节中我们主要分析了chunk_alloc函数,在本小节中,我们先对第一级配置器和第二级配置器的使用做个整理,随后再介绍空间配置器提供的初始化未初始化空间的接口。默认使用的配置器当我们使用vector这些容器时,其实是默认指定了使用的空间配置器的,比如vector在源码中的模板头是这样的template <class T, class Alloc = alloc>,默认指定了配置器为alloc

Move_now的博客 499

通信工程进度计划与措施.docx

通信工程进度计划与措施一、工程施工进度安排工程进度安排根据招标文件提供的规模表,以第一中标人的规模和份额为例,拟定的总体进度计划甘特图如下:施工进度控制甘特图 我公司中标后,将严格按照建设单位的规定的工期把控进度,合理安排施工资源,保证各个专业工程各阶段施工顺利进展,在保障工程质量的前提下确保工程项目按期完成,力争工程提前完工。在工程建设的全过程中,为了取得阶段目标和最终目标的实现,必须对工程建设的全过程根据其组织结构和流程进行明确而详细的分类,制定详细的工程流程,通过对过程的控制和管理,达到对整个工程的控制。从工程建设角度及目前的市场要求,对于所有工程,我公司将严格执行施工管理流程。同时结合公司内部ERP管理流程,提高管理效率。  施工生产要素安排人机料法环是对全面项目管理理论中的五个主要影响因素的简称。人,指制造产品的人员;机,制造产品所用的设备;料,指制造产品所使用的原材料;法,指制造产品所使用的方法;环,指产品制造过程中所处的环境。人员、机器、原料、方法、环境五个方面是必须在工程项目管理中重点关注。Man(人)、Machine(机械)、Mate

SGISTL源码探究-关联式容器:multimap

前言在本小节中我们将分析multimap的实现。它和map的最大的不同之处在于,map不允许重复的键值插入,而multimap允许重复的键值插入,对应到底层的实现,multimap调用的是insert_equal进行插入操作,而map调用的是insert_unique进行插入操作。 另外还有一个不同之处是multimap不支持下标运算,这个也很合理,因为可能有重复键,访问下标时可能就对应了多个值,

Move_now的博客 863

STL源码学习(1)-空间配置器

本文主要剖析了SGI STL的一二级空间配置器,内存基本操作函数

ylh的博客 534

SGI STL二级空间配置器源码剖析

从上面可以看到__STL_DEFAULT_ALLOCATOR通过宏控制有两种实现,一种是allocator< T >,另一种。管理内存,和C++标准库中提供的allocator是一样的,但其二级空间配置器allocator采用了基于freelist。SGI STL包含了一级空间配置器和二级空间配置器,其中一级空间配置器allocator采用malloc和free来。是alloc,这两种分别就是SGI STL的一级空间配置器和二级空间配置器的实现。二级空间配置器分配空间流程。

qq_43804905的博客 160

空间配置器allocator

1、 什么是空间配置器在我看来就是STL容器后面默默工作进行内存管理和分配以及回收的的一个组件,为什么不叫内存配置器?STL源码剖析里说到: 因为空间不一定是内存,空间也可以是磁盘或其他辅助的存储介质。 2、空间配置器的标准接口有哪些 allocator::value_type allocator::pointor allocator::const_pointer allocator::refe

_Dre的博客 375

SGI STL二级空间配置器内存池源码刨析

SGI STL空间配置器介绍 SGI STL包含了一级空间配置器和二级空间配置器,其中一级空间配置器allocator采用malloc和free来管理内存,和C++标准库中提供的allocator是一样的,但其二级空间配置器allocator采用了基于freelist自由链表原理的内存池机制实现内存管理。 SGI STL的二级空间配置器的内存池主要是给 C++的容器底层进行内存管理的使用。 在内存...

weixin_43725202的博客 384

SGI STL 空间配置器(allocator)源码剖析

空间配置器的作用 我们知道,stl中的数据都是放到容器中的,容器需要存储空间,空间配置器就是负责容器存储空间的分配、回收等一系列内存操作。 STL标准规范中描述的allocator模版类的必要声明: Constructors // Constructors used to create allocator objects. allocator(); // Default constr

3025

SGISTL源码阅读三 空间配置器下(内存池memory pool)

SGISTL源码阅读三 空间配置器下(内存池memory pool) 前言 在上一个博客我们讲述了空间配置器的第二级配置器,它的关键点free-lists是依赖于内存池的。在refill中我们通过调用chunk_alloc函数来申请区块,chunk_alloc的作用就是从内存池中取空间给free-lists使用。下面我们通过源码来解读它。 深入源码 template &lt;bool thread...

Lyn&Xx 380

施磊C++ | 项目实战 | SGI STL二级空间配置器源码剖析

C++SGI STL 内存池二级空间配置器源码剖析

m0_74795952的博客 1200

空间配置器(allocator)详解-stl源码剖析学习笔记

空间配置器也就是配置空间,配置容器所需要的空间,该空间获取可以是内存,也可以是磁盘或其他存储介质。

weixin_42853463的博客 1083

SGISTL源码探究-deque容器(上)

前言deque容器比list以及vector容器都要复杂的多。它用两端都有开口的线性空间来存储数据,这样的话在首部操作数据的效率比vector高,以及虽然它的迭代器是random_access_iterator_tag型的,但是并不是原生指针,需要封装,比list和vector的迭代器都要复杂。它实现的机制是利用二级指针,维护一个指针数组map,然后数组中存储的指针指向具体的线性空间。 map并不

Move_now的博客 786
上一篇: (零)阅读源码的工具及参考资料
下一篇: SGISTL源码探究-第一级配置器
UKey_
博客等级 码龄10年 258粉丝 186原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值