动态内存管理类

首先打个广告,对C++后台这一块感兴趣的可以加QQ群大家可以相互学习,有问题大家也可以相互讨论,加群号码745354447。

看C++Primer看到这里的时候心里有点熟悉,因为最近也在看STL源码剖析,觉得和内存分配那一章很吻合,所以看起来很轻松,这里主要是举了一个例子实现vector的一个string的特例。

我觉得首先得从逻辑上梳理一下,
1:这里首先申明了一个构造函数,都用空指针去代替,申明一个StrVec对象后,很自然的就得朝这个对象里去加元素,那么就有push_back这个函数,那么要push_back一个元素,必须得分配内存,然后构造对象,所以就有了chk_n_alloc函数,chk_n_alloc函数首先判断vector大小和本身的capacity大小,如果最开始vector为空,则分配1个元素大小,然后后面每次加入对象的时候,内存开始以2倍扩大。分配了内存那么就要构造对像了,在STL源码剖析里分配内存和构造对象是分开的,所有后续就是构造对象。
2:复制构造函数
还是使用alloc_n_copy分配内存,然后使用uninitialized_copy构造对象
3:拷贝构造函数
拷贝构造函数首先得防止自赋值,所以得使用alloc_n_copy,然后就可以可以释放内存了,使用free函数,然后更新指针值。

完整代码:

/*#!/usr/bin/env
* ******************************************************
* Author       : Gery
* Last modified: 2018-04-08 19:40
* Email        : 2458314507@qq.com
* Filename     : 13_39.cpp
* Description  :
* ********************************************************/
#include<iostream>
#include<new>
#include<stdlib.h>
#include<algorithm>
#include<memory>
using namespace std;

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;}
        void reserve(size_t num);
        void resize(size_t num);
        void resize(size_t,const string&s);
        std::string *begin() const {return elements;}
        std::string *end()const {return first_free;}
        void cir();
    private:
        static std::allocator<std::string>alloc;//分配元素
        //被添加元素的函数所使用
        void chk_n_alloc()
        {
            if(size()==capacity()) reallocate();
        }
        //工具函数,被拷贝构造函数,赋值运算符和析构函数所使用
        std::pair<std::string*,std::string*>alloc_n_copy(const std::string*,const std::string*);
        void free();//销毁元素并释放内存
        void reallocate();//获得更多内存并拷贝已有元素
        void reallocate(size_t newcapacity);
        std::string *elements;//指向数组首元素的指针
        std::string *first_free;//指向数组第一个空闲元素的指针
        std::string *cap;//指向数组尾后位置的指针
};


std::allocator<std::string> StrVec::alloc;

StrVec::~StrVec() { free();}

void StrVec::reserve(size_t num)
{
    if(num>capacity())  reallocate(num);
}


void StrVec::resize(size_t num)
{
    if(num>size())
        while(size()<num)  push_back("");
    else if(num<size())
        while(size()>num)  alloc.destroy(--first_free);
}

void StrVec::resize(size_t num,const string &s)
{
    if(num>size())
        while(size()<num)  push_back(s);
}


pair<string*,string*> StrVec::alloc_n_copy(const string *b,const string *e)
{
    //分配空间保存给定范围内的元素
    auto data = alloc.allocate(e-b);
    //初始化并返回一个pair,该pair由data和uninitialized_copy的返回值构成
    return {data,uninitialized_copy(b,e,data)};
}

StrVec &StrVec::operator=(const StrVec &rhs)//拷贝构造函数
{
    auto data = alloc_n_copy(rhs.begin(),rhs.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}

StrVec::StrVec(const StrVec &rhs)
{
    auto newdata =  alloc_n_copy(rhs.begin(),rhs.end());
    elements = newdata.first;
    first_free = cap = newdata.second;
}

void StrVec::cir()
{
    for(auto p=elements;p!=first_free;p++)
        cout<<*p<<endl;
}

void StrVec::push_back(const std::string&s)
{
    chk_n_alloc();//确保有空间容纳新元素
    alloc.construct(first_free++,s);
}

void StrVec::free()
{
    //不能传递给deallocate一个空指针,如果elements为0,函数什么都不做
    if(elements)//逆序销毁旧元素
    {
        for(auto p=first_free;p!=elements;)  alloc.destroy(--p);
        alloc.deallocate(elements,cap-elements);
    }
}

void StrVec::reallocate(size_t newcapacity)
{
    auto newdata = alloc.allocate(newcapacity);
    auto dest = newdata;//指向新数组中下一个空闲位置
    auto elem = elements;//指向旧数组中下一个元素
    for(size_t i=0;i<size();i++)  alloc.construct(dest++,std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements+newcapacity;
}


void StrVec::reallocate()
{
    auto newcapacity = size()?2*size():1;//分配当前大小两倍的内存空间
    auto newdata = alloc.allocate(newcapacity);
    auto dest = newdata;//指向新数组中下一个空闲位置
    auto elem = elements;//指向旧数组中下一个元素
    for(size_t i=0;i<size();i++)  alloc.construct(dest++,std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements+newcapacity;
}

int main()
{
    StrVec str;
    str.push_back("fanbo");
    cout<<"vector大小"<<str.size()<<"  vector容量"<<str.capacity()<<endl;
    str.push_back("Gery");
    cout<<"vector大小"<<str.size()<<"  vector容量"<<str.capacity()<<endl;
    str.push_back("Kiwi");
    cout<<"vector大小"<<str.size()<<"  vector容量"<<str.capacity()<<endl;
    str.reserve(50);
    cout<<"vector大小"<<str.size()<<"  vector容量"<<str.capacity()<<endl;
    str.cir();
    StrVec str1(str);
    str1.cir();
    StrVec str2 = str1;
    str2.cir();
    return 0;
}

最后输出为:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值