当前位置: 首页 > news >正文

C++ STL中的allocator

绪论

As we all kown,C++中的STL容器使用其内置的std::allocator分配内存。如果我们想要更改STL分配内存的行为,我们不用更改容器的逻辑,只需要更改传入的allocator即可。一直以来,allocator对我来讲都笼罩着一层迷雾,总感觉是一个很复杂很恐怖的东西,最近因为课程原因,需要使用平台特定的内存管理函数(在NVM仿真平台quartz中需要使用其提供的pmalloc和pfree函数管理非易失性内存),就研究了一下std::allocator是怎么实现的。但是认真了解以后发现没有什么神奇的东西。

源码剖析

allocator主要有四个接口:

  • T *allocate(size_t):用void * ::operator new(size_t)分配内存(但是不构造,其实就是对malloc的封装)
  • void deallocate(T*, size_t):使用void ::operator delete(void *)释放内存(其实是对free的封装)
  • void construct(T*, Args&&):使用定位new(placement new::new(void*) T(std::forward<Args>(args)...))在指定内存上进行构造
  • void destroy(T*):调用析构函数(p->~T())进行析构

不过后两者在C++17中被废弃了,在C++20中被删除了,我在stackoverflow上看到一个回答的大概意思是以后应该用std::allocator_traits::construct了。原回答:Why are are std::allocator’s construct and destroy functions deprecated in c++17?

去看了一下STL 的源码,发现std::allocator继承了__allocator_base,然后后者又继承了__gnu_cxx::new_allocator,也就是说其实用的是GNU版本的allocator,我认真阅读了一下__gnu_cxx::new_allocator的实现,发现的确挺简洁,没有什么特殊的东西,通过把里面的宏改成普通的关键字,删除掉我觉得没有什么用的版本判断,就可以得到一个简单的allocator实现:

// Copyright(C), Edward-Elric233
// Author: Edward-Elric233
// Version: 1.0
// Date: 2022/10/25
// Description: __gnu__cxx::new_allocator
#ifndef TEMP_PALLOCATOR_H
#define TEMP_PALLOCATOR_H

#include "utils.h"
#include <new>
#include <type_traits>


namespace edward
{

    using std::size_t;
    using std::ptrdiff_t;


    /**
     *  @brief  An allocator that uses global new, as per [20.4].
     *  @ingroup allocators
     *
     *  This is precisely the allocator defined in the C++ Standard.
     *    - all allocation calls operator new
     *    - all deallocation calls operator delete
     *
     *  @tparam  T  Type of allocated object.
     */
    template<typename T>
    class pallocator
    {
    public:
        typedef size_t     size_type;
        typedef ptrdiff_t  difference_type;
        typedef T*       pointer;
        typedef const T* const_pointer;
        typedef T&       reference;
        typedef const T& const_reference;
        typedef T        value_type;

        template<typename T1>
        using other = pallocator<T1>;



        // _GLIBCXX_RESOLVE_LIB_DEFECTS
        // 2103. propagate_on_container_move_assignment
        typedef std::true_type propagate_on_container_move_assignment;

        constexpr pallocator() noexcept { }

        constexpr
        pallocator(const pallocator&) noexcept { }

        template<typename T1>
        constexpr
        pallocator(const pallocator<T1>&) noexcept { }

        ~pallocator() noexcept { }

        pointer
        address(reference __x) const noexcept
        { return std::__addressof(__x); }

        const_pointer
        address(const_reference __x) const noexcept
        { return std::__addressof(__x); }

        // NB: __n is permitted to be 0.  The C++ standard says nothing
        // about what the return value is when __n == 0.
        [[nodiscard]] pointer   //cannot discard return value!!!
        allocate(size_type __n, const void* = static_cast<const void*>(0))
        {
            if (__n > this->max_size())
                throw std::bad_alloc();
            print("allocate", __n * sizeof(T), "bytes");
            return static_cast<T*>(::operator new(__n * sizeof(T)));
        }

        // __p is not permitted to be a null pointer.
        void
        deallocate(pointer __p, size_type __n)
        {
            print("deallocate", __n * sizeof(T), "bytes");
            ::operator delete(__p);
        }

        size_type
        max_size() const noexcept
        {
            return size_t(__PTRDIFF_MAX__) / sizeof(T);
        }

        template<typename _Up, typename... _Args>
        void
        construct(_Up* __p, _Args&&... __args)
        noexcept(std::is_nothrow_constructible<_Up, _Args...>::value)
        { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }

        template<typename _Up>
        void
        destroy(_Up* __p)
        noexcept(std::is_nothrow_destructible<_Up>::value)
        { __p->~_Up(); }
        template<typename _Up>
        friend bool
        operator==(const pallocator&, const pallocator<_Up>&) noexcept
        { return true; }

        template<typename _Up>
        friend bool
        operator!=(const pallocator&, const pallocator<_Up>&) noexcept
        { return false; }
    };

} // namespace



#endif //TEMP_PALLOCATOR_H

我在allocatedeallocate函数中添加了打印函数,utils.h头文件的获取可以看一下我之前的博客:C++ 工具函数库

参考资料

  • 第10篇:C++ 堆内存管理器-allocator
  • 《C++ primer》第5版 12.2.2节 allocator类

相关文章:

  • GitHub提交代码超时解决方案 | 配置SSH连接
  • 火山引擎 RTC 全球化架构设计
  • 软考知识点---13语言处理程序基础
  • 生成keystore以及导出keystore公钥,私钥信息
  • 黑马学SpringCloud-Feign
  • 基于springboot的校园二手网站
  • 对于一个即将上线的网站,如何测试
  • 手把手教你搭建SpringCloudAlibaba之Nacos服务集群配置
  • 【数据分析】多重分形去趋势波动分析附matlab代码
  • Spring Cloud LoadBalancer--负载均衡的原理(源码分析)
  • Prometheus基础概念介绍
  • SDNU_ACM_ICPC_2022_Weekly_Practice_1rd「个人赛」题解
  • 4种数据仓库建模方法
  • 离线数仓 (八) --------- 数仓分层
  • 【JVM技术专题】360度无死角认识volatile机制
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • Angularjs之国际化
  • CSS中外联样式表代表的含义
  • iOS小技巧之UIImagePickerController实现头像选择
  • javascript从右向左截取指定位数字符的3种方法
  • Java方法详解
  • MySQL用户中的%到底包不包括localhost?
  • PHP 7 修改了什么呢 -- 2
  • PHP那些事儿
  • Python语法速览与机器学习开发环境搭建
  • vue-router 实现分析
  • Webpack 4 学习01(基础配置)
  • 动态规划入门(以爬楼梯为例)
  • 机器学习 vs. 深度学习
  • # 数论-逆元
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (vue)页面文件上传获取:action地址
  • (二)丶RabbitMQ的六大核心
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (四) 虚拟摄像头vivi体验
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • ****Linux下Mysql的安装和配置
  • .Net 6.0 处理跨域的方式
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • .NET牛人应该知道些什么(2):中级.NET开发人员
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [ C++ ] STL priority_queue(优先级队列)使用及其底层模拟实现,容器适配器,deque(双端队列)原理了解
  • [ 隧道技术 ] cpolar 工具详解之将内网端口映射到公网
  • [Android]Android开发入门之HelloWorld
  • [C# WPF] DataGrid选中行或选中单元格的背景和字体颜色修改
  • [c]统计数字
  • [C++]Leetcode17电话号码的字母组合
  • [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子
  • [DM复习]关联规则挖掘(下)
  • [ffmpeg] aac 音频编码
  • [FROM COM张]如何解决Nios II SBTE中出现的undefined reference to `xxx'警告