首页 > 其他分享 >空间配置器allocator

空间配置器allocator

时间:2024-10-22 12:20:48浏览次数:3  
标签:last int rhs 配置 ._ 空间 first allocator size

空间配置器allocator

自己定义的vector容器

缺点

  • 构造容器的时候使用new导致分配内存的同时也调用构造函数,析构容器的时候使用delete将所有的元素进行析构。我们想要的是在使用容器的时候,如果没有元素入栈,就不会进行多余的构造;同时对容器进行析构时,也仅仅析构仅有的几个元素。
#include <iostream>

template<typename T>
class vector {
public:
    vector(int size) {
        _first = new T[size];
        _last = _first;
        _end = _first + size;
    }
    vector(const vector<T>& rhs) // 容器的拷贝构造函数
    {
        int size = rhs._end - rhs._first;
        int len = rhs._last - rhs._first;
        _first = new T[size];

        for (int i = 0; i < len; i++)
        {
            _first[i] = rhs._first[i];
        }
        _last = _first + len;
        _end = _first + size;
    }

    vector& operator=(const vector<T>& rhs) // 赋值运算重载
    {
        if (this == &rhs)
            return *this;
        delete[]_first;

        int size = rhs._end - rhs._first;
        int len = rhs._last - rhs._first;
        _first = new T[size];

        for (int i = 0; i < len; i++)
        {
            _first[i] = rhs._first[i];
        }
        _last = _first + len;
        _end = _first + size;

        return *this;
    }
    ~vector()
    {
        delete[]_first;
        _first = _last = _end = nullptr;
    }

    // 向容器末尾添加参数
    void pushback(T val)
    {
        if (full())
        {
            expand();
        }
        *_last++ = val;
    }

    void popback()
    {
        if (empty())
            return;
        _last--;
    }

    T back()  // 返回容器末尾的元素值
    {
        return *_last;
    }

    bool full()
    {
        return _last == _end;
    }
    bool empty()
    {
        return _first == _last;
    }
    T top()
    {
        return *(_last - 1);
    }

private:
    void expand() // 容器二倍扩容
    {
        int size = _end - _first;
        T* tmp = new T[2 * size];
        int len = _last - _first;
        for (int i = 0; i <= len; i++)
        {
            tmp[i] = _first[i];
        }

        delete[]_first;
        _first = tmp;
    }

    T* _first; // 指向容器起始元素地址
    T* _last;  // 指向容器末尾元素地址
    T* _end;   // 指向分配内存某位地址
};

class Test
{
public:
    Test() { std::cout << "Test()::construct" << std::endl; }
    ~Test() { std::cout << "~Test()::construct" << std::endl; }
    Test(const Test& rhs) { std::cout << " Test(const Test& rhs)::construct" << std::endl; }
private:

};

int main()
{
    vector<Test>vec(10);
    return 0;
}


使用allocator空间配置器

  • 通过定义空间配置器,使内存开辟、内存释放与构造、析构分离,这样可以使得定义容器时不会直接在容器内部调用构造函数,而是在为容器添加元素或者删除元素时调用构造函数或者析构函数

  • 空间配置器组成:

    • 内存分配T* allocate(size_t size)

      T* allocate(size_t size) {
          T *ptr = (T*)malloc(sizeof(T) * size);
          return ptr;
      }
      
    • 内存释放void deallocate(T *p)

      // 释放内存空间
      void deallocate(T *ptr)
      {
          free(ptr);
      }
      
    • 对象构造 void construct(T *p, const T &val)

      // 构造对象
      void construct(T *ptr, const T &val)
      {
          new (ptr) T(val); // 定位new
      }
      
    • 对象析构 void destroy(T *p)

      // 析构对象
      void destroy(T *ptr)  
      {
          ptr->~T();
      }
      

整体代码

#include <iostream>

// 定义空间配置器 ;SGI二级空间配置器:内存池
template<typename T>
class Allocator {
public:
    // 开辟内存空间
    T* allocate(size_t size) {
        T *ptr = (T*)malloc(sizeof(T) * size);
        return ptr;
    }

    // 释放内存空间
    void deallocate(T *ptr)
    {
        free(ptr);
    }

    // 构造对象
    void construct(T *ptr, const T &val)
    {
        new (ptr) T(val); // 定位new
    }

    // 析构对象
    void destroy(T *ptr)  
    {
        ptr->~T();
    }
    
};

template<typename T, typename Alloc = Allocator<T>>
class vector {
public:
    vector(int size) {
        
        _first = allocator_.allocate(size);
        _last = _first;
        _end = _first + size;
    }

    vector(const vector<T>& rhs) // 容器的拷贝构造函数
    {
        int size = rhs._end - rhs._first;
        int len = rhs._last - rhs._first;

        _first = allocator_.allocate(size);

        for (int i = 0; i < len; i++)
        {
            allocator_.construct(_first + i, rhs._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
    }

    vector& operator=(const vector<T>& rhs) // 赋值运算重载
    {
        if (this == &rhs)
            return *this;
        delete[]_first;

        int size = rhs._end - rhs._first;
        int len = rhs._last - rhs._first;
        
        _first = allocator_.allocate(size);

        for (int i = 0; i < len; i++)
        {
            allocator_.construct(_first + i, rhs._first[i]);
        }
        _last = _first + len;
        _end = _first + size;

        return *this;
    }

    ~vector()
    {
        //delete[]_first;
        for (int i = 0; i < _last - _first; i++)
        {
            allocator_.destroy(_first + i);
        }
        allocator_.deallocate(_first);
        _first = _last = _end = nullptr;
    }

    // 向容器末尾添加参数
    void pushback(const T &val)
    {
        if (full())
        {
            expand();
        }
        //*_last++ = val;
        allocator_.construct(_last++, val);
    }

    void popback()
    {
        if (empty())
            return;
        --_last;
        allocator_.destroy(_last);
    }

    T back()  // 返回容器末尾的元素值
    {
        return *(_last - 1);
    }

    bool full()
    {
        return _last == _end;
    }

    bool empty()
    {
        return _first == _last;
    }
    T top()
    {
        return *(_last - 1);
    }

private:
    void expand() // 容器二倍扩容
    {
        int size = _end - _first;

        T* tmp = allocator_.allocate(size * 2);

        int len = _last - _first;
        for (int i = 0; i <= len; i++)
        {
            allocator_.construct(tmp + i, _first[i]);
        }

        for (int i = 0; i <= len; i++)
        {
            allocator_.destroy(_first + i);
        }
        allocator_.deallocate(_first);

        _first = tmp;
        _last = _first + len;
        _end = _first + size * 2;
    }

    Alloc allocator_;

    T* _first; // 指向容器起始元素地址
    T* _last;  // 指向容器末尾元素地址
    T* _end;   // 指向分配内存某位地址
};

class Test
{
public:
    Test() { std::cout << "Test()::construct" << std::endl; }
    ~Test() { std::cout << "~Test()::construct" << std::endl; }
    Test(const Test& rhs) { std::cout << " Test(const Test& rhs)::construct" << std::endl; }
private:

};

int main()
{
    vector<Test>vec(10);

    Test t1;
    Test t2;
    Test t3;
    std::cout << "-----------------" << std::endl;
    vec.pushback(t1);
    vec.pushback(t2);
    vec.pushback(t3);
    std::cout << "-----------------" << std::endl;
    vec.popback();
    std::cout << "-----------------" << std::endl;
    return 0;
}

标签:last,int,rhs,配置,._,空间,first,allocator,size
From: https://blog.csdn.net/weixin_43459437/article/details/143148899

相关文章

  • Jenkins打包Unity游戏环境变量配置
    Jenkins打包Unity游戏失败,通过报错日志会查找到sdk环境有问题,解决sdk的环境问题后会出现ndk环境有问题,为了解决这两个问题导致的打包失败需要在Jenkins中配置环境变量打开Jenkins首页,选中ManagerJenkins,再点击System选项找到全局属性,勾选Environmentvariables选项点击......
  • nginx配置
    为什么用postman请求本地的接口前面是http不是httpshttp://localhost:18080/api/v3/process/selectSubTableData 在开发和测试环境中,使用HTTP而不是HTTPS来请求本地接口是非常常见的做法,原因包括:简化配置:在本地开发时,通常不需要设置HTTPS,这样可以避......
  • Linux环境下Tomcat的安装与配置详细指南
    ApacheTomcat是一个广泛使用的开源JavaServlet容器和Web服务器,适用于运行JavaWeb应用程序。本指南将详细介绍如何在Linux环境中安装和配置Tomcat,包括必要的前提条件、下载安装、配置环境变量、设置为系统服务以及基本的安全配置。目录前提条件安装Java环境创建Tomcat用户......
  • CH9120串口配置模式程序参考
    测试工具:CH32v307+CH9120编译IDE:MounRiver相关文档:https://files.cnblogs.com/files/blogs/808422/CH9120%E4%B8%B2%E5%8F%A3%E6%8E%A7%E5%88%B6%E6%8C%87%E4%BB%A4%E9%9B%86.zip?t=1727600534&download=true参考代码:https://files.cnblogs.com/files/blogs/808422/CH912x%E4%......
  • 3. 从0到1搭建DeltaLake大数据平台 - 安装配置Hadoop
    要在你的Spark集群上安装和配置HDFS(Hadoop分布式文件系统),可以按照以下步骤进行:1.安装Hadoop1.1下载Hadoop选择一个合适的Hadoop版本(例如Hadoop3.x),下载并解压缩:wgethttps://downloads.apache.org/hadoop/common/hadoop-x.y.z/hadoop-x.y.z.tar.gztar-xzfhadoo......
  • 在 CentOS 上安装和配置 GeoServer并配置为系统服务
    CentOS上安装和配置GeoServer作为系统服务1.安装GeoServer下载GeoServer:从GeoServer官方网站下载最新版本的GeoServer压缩包。解压文件:tar-zxvfgeoserver-2.25.3-bin.zip-C/usr/local2.创建systemd服务文件创建服务文件:sudonano/etc/syste......
  • 华为鸿蒙开发:掌握应用包名、图标、版本及权限配置
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在华为鸿蒙HarmonyOS的开发过程中,正确......
  • 利用 Python 进行地理空间数据处理的工具
    本文将介绍九个常用的地理空间数据处理工具,包括GeoPandas、Fiona、Rasterio、Shapely、Pyproj、Descartes、Rtree、Geopy和Folium。这些工具覆盖了从地理空间数据读写、几何操作、坐标转换到地图绘制等多个方面,是地理信息系统(GIS)领域不可或缺的技术栈。1.GeoPandas:地理数据......
  • 在Windows操作系统中,配置系统服务和检查服务的状态是确保系统正常运行的关键步骤。以
    在Windows操作系统中,配置系统服务和检查服务的状态是确保系统正常运行的关键步骤。以下是关于系统服务、PrintSpooler服务的工作状态、身份增强校验失败和Guest账户未激活的详细说明:1.系统服务概述Windows系统服务是后台运行的程序,用于执行系统管理任务或支持应用程序的运行。......
  • OpenCV-Python 颜色空间转换
    一、颜色空间转换importcv2importnumpyasnpimg=cv2.imread('lena.jpg')#转换成灰度图img_gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)cv2.imshow('img',img)cv2.imshow('gray',img_gray)cv2.waitKey(0)颜色转换其实是数学运算,如灰度化最常用的是:gray......