STL源码:分配器 allocator

本文深入探讨C++中的内存管理机制,特别是allocator的概念及其在STL容器中的应用。介绍了operator new与malloc的区别,以及allocator如何通过减少malloc调用次数和额外开销来优化内存分配。

operator new() 和 malloc()

在这里插入图片描述
operator new()就是调用malloc来申请内存空间
所有的分配内存操作最终都将落在 malloc 上。malloc分配的实际内存要比申请的内存大,因为有附加信息,附加信息一般是固定的

allocators(VC6 BC5 G2.9 G4.9)

  1. VC6版本
    在这里插入图片描述

  2. BC5版本

在这里插入图片描述

  1. G2.9版本

在这里插入图片描述
G2.9虽然定义了和其他版本分配器类似的<defalloc.h>,但是未使用它。G2.9使用了一种改进的allocator,即<stl_alloc.h>

allocator的目标:尽量减少malloc的次数、减少额外开销。<stl_alloc.h>能够减少额外开销:

在这里插入图片描述

减少额外开销:
额外开销来自于对该块空间的大小等的说明(Cookie),G2.9通过以下方法节省额外开销:
G2.9实际上的allocator是维护n个链表,每一个链表负责某一个特定大小的区块,如第1个链表1个字节的分配,第2个负责2个字节的分配,第3个负责3个字节的分配…没有时再去和操作系统申请并切割
同一个链表上的内存块可以省掉一些额外开销,如大小等信息就不必再加上

  1. G4.9版本(最新版本)

G4.9又摒弃了G2.9的设计,用了无特殊设计的VC6模式,如下

在这里插入图片描述

但G2.9版本也被保留了

在这里插入图片描述

allocator使用方法

int main() {
   
   
    std::allocator<std::string> alloc; // 可以分配string的allocator对象
    
    int n{
   
   5};
    auto const p = alloc.allocate(n); // 分配n个未初始化的string

    auto q = p;
    alloc.construct(q++); // *q为空字符串
    alloc.construct(q++, 10, 'o'); // *q为cccccccccc
    alloc.construct(q++, "hello"); // *q为hello

    std::cout << *p << std::endl; // 正确:使用string的输出运算符
    //std::cout << *q << std::endl; // 错误:q指向未构造的内存
    std::cout << p[0] << std::endl;
    std::cout << p[1] << std::endl;
    std::cout << p[2] << std::endl;

    while (q != p) {
   
   
        alloc.destroy(--q); // 释放我们真正构造的string
    }

    alloc.deallocate(p, n);

    return 0;
}

allocator源码详解

源文件结构

这里面还有很多底层函数没找到实现在哪里,只能先看大概

1. 在QT5.8中,vector定义如下

template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc>{
   
   }

template<typename _Tp, typename _Alloc>
struct _Vector_base{
   
   }

默认使用std::allocator分配器

2. allocator结构说明

在这里插入图片描述

(1)以qt5.8的allocator.h为例,最上一层定义了多个allocator,其中一个如下

在这里插入图片描述

(2)可以看到上面的allocator类中没有标准规定的deallocator等函数。但是它继承了基类**__allocator_base**,而该基类出现在c++allocator.h中,如下:

template<typename _Tp>
using __allocator_base = __gnu_cxx::new_allocator<_Tp>;

(3)进一步找到**<new_allocator.h>**文件,可以发现里面定义了allocator所需要的所有必须类,包括在deallocator在内。___gnu_cxx::new_allocator<_Tp>是大部分编译器实现allocator的最底层
在这里插入图片描述

allocator基类:new_allocator

参考:https://zhuanlan.zhihu.com/p/354191253

https://blog.csdn.net/mei_true/article/details/113951160

c++默认的内存分配器继承于___gnu_cxx::new_allocator<_Tp>,它有两个任务

  • 分配对象内存、初始化对象
  • 析构对象、释放对象内存

源码如下:

//使用std中size_t和ptrdiff_t定义,为了程序的可移值性适应不同平台
//size_t表示unsigned类型,ptrdiff_t保存两个指针相减的结果
using std::size_t;
using std::ptrdiff_t;
//1. 定义new_allocator模板
template<typename _Tp>
class new_allocator{
   
   
public:
    typedef size_t     size_type;//类型定义,__allocator_traits中介绍
    typedef ptrdiff_t  difference_type;//元素之间的距离
    typedef _Tp*       pointer;//指针类型
    typedef const _Tp* const_pointer;
    typedef _Tp&       reference;//左值引用类型(左值就是非临时变量)
    typedef const _Tp& const_reference;
    typedef _Tp        value_type;//元素类型
	
    //2. rebind,结构体模板(重要函数)
    template<typename _Tp1>
    struct rebind{
   
    
        typedef new_allocator<_Tp1> other; 
    };
	
    //3. 检测是否支持C++11标准;里面的变量含义将在后面内存学习中详细解答
    #if __cplusplus >= 201103L
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // 2103. propagate_on_container_move_assignment
    typedef std::true_type propagate_on_container_move_assignme
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值