返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++中allocator类使用示例
  • 468
分享到

C++中allocator类使用示例

2024-04-02 19:04:59 468人浏览 泡泡鱼
摘要

目录动态内存管理StrVec类实现细节总结动态内存管理 之前我们讲述过动态内存的开辟,可以通过new, malloc,以及alloc等方式,本文通过介绍alloc方式,构造一个Str

动态内存管理

之前我们讲述过动态内存的开辟,可以通过new, malloc,以及alloc等方式,本文通过介绍alloc方式,构造一个StrVec类,这个类的功能类似于一个vector,实现字符串的管理,其中包含push一个字符串,动态扩容,析构,回收内存等操作。

StrVec类实现细节

StrVec类实现如下

class StrVec
{
public:
    //无参构造函数
    StrVec() : elements(nullptr), first_free(nullptr),
               cap(nullptr) {}
    //拷贝构造函数
    StrVec(const StrVec &);
    //拷贝赋值运算符
    StrVec &operator=(const StrVec &);
    //析构函数
    ~StrVec();
    //拷贝元素
    void push_back(const std::string &);
    //返回元素个数
    size_t size() const { return first_free - elements; }
    //返回总容量
    size_t capacity() const { return cap - elements; }
    //返回首元素地址
    std::string *begin() const
    {
        return elements;
    }
    //返回第一个空闲元素地址
    //也是最后一个有效元素的下一个位置
    std::string *end() const
    {
        return first_free;
    }

private:
    //判断容量不足开辟新空间
    void chk_n_alloc()
    {
        if (size() == capacity())
            reallocate();
    }
    //重新开辟空间
    void reallocate();
    // copy指定范围的元素到新的内存中
    std::pair<std::string *, std::string *> alloc_n_copy(
        const std::string *, const std::string *);
    //释放空间
    void free();
    //数组首元素的指针
    std::string *elements;
    //指向数组第一个空闲元素的指针
    std::string *first_free;
    //指向数组尾后位置的指针
    std::string *cap;
    //构造string类型allocator静态成员
    static std::allocator<std::string> alloc;
};

1 elements成员,该成员指向StrVec内部数组空间的第一个元素
2 first_free成员指向第一个空闲元素,也就是有效元素的下一个元素,该元素开辟空间但未构造。
3 cap 指向最后一个元素的下一个位置。
4 alloc为静态成员,主要负责string类型数组的开辟工作。
5 无参构造函数将三个指针初始化为空,并且默认够早了alloc。
6 alloc_n_copy私有函数的功能是将一段区域的数据copy到新的空间,
并且返回新开辟的空间地址以及第一个空闲元素的地址(第一个未构造元素的地址)。
7 chk_n_alloc私有函数检测数组大小是否达到容量,如果达到则调用reallocate重新开辟空间。
8 reallocate重新开辟空间
9 capacity返回总容量
10 size返回元素个数
11 push_back 将元素放入开辟的类似于数组的连续空间中。
12 begin返回首元素地址
13 end返回第一个空闲元素地址,也是最后一个有效元素的下一个位置
无论我们实现push操作还是拷贝构造操作,都要实现realloc,当空间不足时要开辟空间将旧数据移动到新的数据

//重新开辟空间
void StrVec::reallocate()
{
    string *newdata = nullptr;
    //数组为空的情况
    if (elements == nullptr || cap == nullptr || first_free == nullptr)
    {
        newdata = alloc.allocate(1);
        // elements和first_free都指向首元素
        elements = newdata;
        first_free = newdata;
        // cap指向数组尾元素的下一个位置。
        cap = newdata + 1;
        return;
    }
    //不为空则扩充两倍空间
    newdata = alloc.allocate(size() * 2);
    //新内存空闲位置
    auto dest = newdata;
    //旧内存有效位置
    auto src = elements;
    //通过移动操作将旧数据放到新内存中
    for (size_t i = 0; i != size(); ++i)
    {
        alloc.construct(dest++, std::move(*src++));
    }
    //移动后旧内存数据无效,一定要删除
    free();
    //更新数据位置
    elements = newdata;
    //更新第一个空闲位置
    first_free = dest;
    //更新容量
    cap = elements + size() * 2;
}

reallocate函数内部判断是否为刚初始化指针却没开辟空间的空数组,如果是则开辟1个大小的空间。
否则则开辟原有空间的两倍,将旧数据移动到新空间,采用了std::move操作,这么做减少拷贝造成的性能开销。
move之后原数据就无效了,所以要调用私有函数free()进行释放。我们实现该free操作

//释放操作
void StrVec::free()
{
    //判断elements是否为空
    if (elements == nullptr)
    {
        return;
    }

    auto dest = elements;
    //要先遍历析构每一个对象
    for (size_t i = 0; i < size(); i++)
    {
        // destroy会调用每一个元素的析构函数
        alloc.destroy(dest++);
    }
    //再整体回收内存
    alloc.deallocate(elements, cap - elements);
}

先通过遍历destroy销毁内存,从而调用string的析构函数,最后在deallocate回收内存。

// copy指定范围的元素到新的内存中,返回新元素的地址和第一个空闲元素地址的pair
std::pair<std::string *, std::string *> StrVec::alloc_n_copy(
    const std::string *b, const std::string *e)
{
    auto newdata = alloc.allocate(e - b);
    //将原数据用来初始化新空间
    auto first_free = uninitialized_copy(b, e, newdata);
    return {newdata, first_free};
}

这样利用alloc_n_copy,我们就可以实现拷贝构造和拷贝赋值了

//拷贝构造函数
StrVec::StrVec(const StrVec &strtmp)
{
    //将形参数据拷贝给自己
    auto rsp = alloc_n_copy(strtmp.begin(), strtmp.end());
    //更新elements, cap,first_free
    elements = rsp.first;
    first_free = rsp.second;
    cap = rsp.second;
}

但是拷贝赋值要注意一点,就是自赋值的情况,所以我们提前判断是否为自赋值,如不是则进行和拷贝构造相同的操作

//拷贝赋值运算符
StrVec &StrVec::operator=(const StrVec &strtmp)
{
    //防止自赋值
    if (this == &strtmp)
    {
        return *this;
    }
    //将形参数据拷贝给自己
    auto rsp = alloc_n_copy(strtmp.begin(), strtmp.end());
    //更新elements, cap,first_free
    elements = rsp.first;
    first_free = rsp.second;
    cap = rsp.second;
}

我们可以利用free实现析构函数

//析构
StrVec::~StrVec()
{
    free();
}

接下来我们实现push_back,将指定字符串添加到数组空间,以及抛出元素

//添加元素
void StrVec::push_back(const std::string &s)
{
    chk_n_alloc();
    alloc.construct(first_free++, s);
}

//抛出元素
void StrVec::pop_back(std::string &s)
{
    if (first_free == nullptr)
    {
        return;
    }

    if (size() == 1)
    {
        
        s = *elements;
        alloc.destroy(elements);
        first_free = nullptr;
        elements = nullptr;
        return;
    }

    s = *(--first_free);
    alloc.destroy(first_free);
}

接下来实现测试函数,测试上述操作

void test_strvec()
{
    auto str1 = StrVec();
    str1.push_back("hello zack");
    StrVec str2(str1);
    str2.push_back("hello rolin");
    StrVec str3 = str1;
    string strtmp;
    str3.pop_back(strtmp);
}

在主函数调用上面test_strvec,运行稳定。

总结

本文通过allocator实现了一个类似于vector的类,管理string变量。演示了拷贝构造,拷贝赋值要注意的事项,同时演示了如何手动开辟内存并管理内存空间。

到此这篇关于C++中allocator类使用示例的文章就介绍到这了,更多相关C++ allocator类内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++中allocator类使用示例

本文链接: https://lsjlt.com/news/138746.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++中allocator类使用示例
    目录动态内存管理StrVec类实现细节总结动态内存管理 之前我们讲述过动态内存的开辟,可以通过new, malloc,以及alloc等方式,本文通过介绍alloc方式,构造一个Str...
    99+
    2024-04-02
  • C++中std::allocator的使用案例详解
    标准库中包含一个名为allocator的类,允许我们将分配和初始化分离。使用allocator通常会提供更好的性能和更灵活的内存管理能力。    ...
    99+
    2024-04-02
  • CSS中类名的使用示例
    CSS中类名的使用示例,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。以下以数字开头的 CSS 类名不会生效:.1st{   &nb...
    99+
    2023-06-08
  • C#类使用实例分析
    这篇“C#类使用实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C#类使用实例分析”文章吧。实例using ...
    99+
    2023-06-17
  • C++中类与对象的示例分析
    这篇文章将为大家详细讲解有关C++中类与对象的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言:C 语言是面向过程的,关注的是过程,分析出求解的步骤,通过函数逐步调用解决问题。C++是基于面向对...
    99+
    2023-06-22
  • C语言中指针的使用示例
    这篇文章给大家分享的是有关C语言中指针的使用示例的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、指针的作用运用指针可以有效地表达一些复杂地数据结构,比如系统地动态分配内存、消息机制、任务调度、定时器等等。掌握指...
    99+
    2023-06-29
  • C++BoostAny示例分析使用
    目录一、提要二、Boost.Any示例一、提要 强类型语言,例如 C++,要求每个变量都有一个特定的类型来定义它可以存储什么样的信息。其他语言,例如 JavaScript,允许开发人...
    99+
    2022-11-13
    C++ Boost Any C++ Boost Any示例
  • TypeScript类型使用示例剖析
    目录JavaScript的内置类型 VS TypeScript内置类型元祖接口interfaceinterface和type有什么区别?枚举怎么让Babel支持const enum字...
    99+
    2023-05-18
    TypeScript类型剖析 TypeScript 类型示例
  • C++中静态数据成员使用示例
    #include<iostream>//尝试静态数据成员 using namespace std; class easy { private: int num1; i...
    99+
    2024-04-02
  • JAVA biginteger类bigdecimal类的使用示例学习
    目录biginteger类的使用BigInteger案例代码bigdecimal类的使用BigDecimal的案例代码biginteger类的使用 A:BigInteger的概述 &...
    99+
    2024-04-02
  • Python中使用matplotlib绘制各类图表示例
    折线图 折线图是一种用于表示数据随时间、变量或其他连续性变化的趋势的图表。通过在横轴上放置时间或如此类似的连续变量,可以在纵轴上放置数据点的值,从而捕捉到数据随时间发生的变化。折线图可以用于比较不同变...
    99+
    2023-09-13
    python matplotlib 开发语言
  • Java中的vector类使用方法示例详解
     基本操作示例VectorApp.javaimport java.util.Vector; import java.lang.*; import java.util.Enumeration; public class Vector...
    99+
    2023-05-31
    java vector ava
  • C#中Convert类解决方法的示例分析
    这篇文章主要介绍了C#中Convert类解决方法的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。你有一个包含二进制数、八进制数、十进制数或十六进制数的字符串。你需要把...
    99+
    2023-06-18
  • C语言中数据类型的示例分析
    这篇文章将为大家详细讲解有关C语言中数据类型的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。(壹) 数据类型介绍前面我们已经学习了基本的内置类型,以及他们所占存储空间的大小。:类型的意义...
    99+
    2023-06-29
  • C++中Queue队列类模版的示例分析
    这篇文章主要介绍C++中Queue队列类模版的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1.队列的介绍队列的定义队列(Queue)是一种线性存储结构。它有以下几个特点:按照"先进先出(FIFO,...
    99+
    2023-06-29
  • C#中using关键字的使用方法示例
    目录1 :using 指令(命名空间)2 :using 语句(1 ):using (ResourceType Identifier = Expression ) State...
    99+
    2024-04-02
  • C#中类怎么使用
    这篇文章主要介绍了C#中类怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#中类怎么使用文章都会有所收获,下面我们一起来看看吧。实例化在对类进行访问时,需要将类进行实例化。并产生一个对象。可以使用关键字...
    99+
    2023-07-02
  • java Scanner类的使用示例代码
    Scanner类简介 Java 5添加了java.util.Scanner类,这是一个用于扫描输入文本的新的实用程序。它是以前的StringTokenizer和Matcher类之间...
    99+
    2024-04-02
  • Java使用Unsafe类的示例详解
    Unsafe 对象提供了非常底层的,操作内存、线程的方法,相当于开了后门。 在atomic类中CAS实现、LockSupport中park unpark的底层都调用了UnSafe中的...
    99+
    2024-04-02
  • Java优秀类库Hutool使用示例
    目录介绍如何使用总结介绍   日常的业务开发,我们会重复编写一些代码:日期和字符串相互转换、发送Http请求调用接口、拷贝对象等。所以为了避免重复编写,项目中会封...
    99+
    2023-02-21
    Java Hutool Java Hutool工具包
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作