动态内存管理类

内存管理类需要包括以下几个基本操作的正确性

  1. 添加元素:判断管理的空间大小是否能够添加新元素,如不够,则使用allocator分配内存,并将旧数据移动到新内存,然后释放旧内存,并更新内存首指针、第一个可用内存指针、尾指针位置。
  2. 对象拷贝:使用allocator的allocate分配内存,相关的uninitialized_copy拷贝元素到新的位置,并更新内存首指针、第一个可用内存指针、尾指针位置。
  3. 内存释放:使用allocator的destroy销毁内存,并使用deallocate执行内存回收操作

注意:静态对象必须首先在类外进行初始化操作。

//uninitialized_copy被编译器认为是不安全的,这语句是让编译器停止警告,放到第一行
#pragma warning(disable : 4996)
#include<iostream>
#include<string>
#include<memory>
using namespace std;
class StrVec
{
public:
    StrVec() :
        elements(nullptr), first_free(nullptr), cap(nullptr)
    {
    }
    //拷贝构造函数
    StrVec(const StrVec& s)
    {
        auto newdata = alloc_n_copy(s.begin(), s.end());
        elements = newdata.first;
        first_free = cap = newdata.second;
    }
    //拷贝赋值运算
    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() { free(); }
    //添加对象函数
    void push_back(const string& str)
    {
        chk_n_alloc();
        //在first_free位置构造元素
        alloc.construct(first_free++, str);
    }
    //输出内容
    void print(ostream& os)
    {
        for (auto pos = begin(); pos != end(); pos++)
            os << *pos << endl;
    }
    size_t size() const { return first_free - elements; }
    size_t capacity() const { return cap - elements; }
    string* begin() const { return elements; }
    string* end() const { return first_free; }

private:
    static allocator<string> alloc;
    void chk_n_alloc()
    {
        if (size() == capacity()) 
            reallocate();
    }
    //工具函数,被拷贝构造函数、赋值运算符和析构函数使用
    std::pair<string*, string*>alloc_n_copy(const string*b, const string*e)
    {
        auto data = alloc.allocate(e - b);
        return{ data,uninitialized_copy(b,e,data) };
    }
    //销毁元素,释放内存
    void free()
    {
        //不能传递给一个空指针,为0什么也不做
        if (elements)
        {
            for (auto p = first_free; p != elements;)
                alloc.destroy(--p);
            alloc.deallocate(elements, cap - elements);
        }
    }
    //获得更多内存,拷贝已有元素
    void 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++)
            //移动的时候,通过move函数转换为右值引用,使用了移动构造函数构造对象
            alloc.construct(dest++, std::move(*elem++));
        free();//移动完成,释放旧内存
        //更新数据结构,换到新元素
        elements = newdata;
        first_free = dest;
        cap = elements + newcapacity;
    }
    //指向数组首元素指针
    string *elements;
    //指向数组第一个空闲元素的指针
    string *first_free;
    //指向数组尾后位置
    string *cap;
};
allocator<string> StrVec::alloc;

使用时

int main()
{
    {
        StrVec strVec;
        strVec.push_back("asdfasdf");
        //strVec.push_back("123456");
        //strVec.push_back("!@#$%^&");
        //strVec.push_back("123123!@#$%^&");
        auto strVec1 = strVec;
        strVec1.push_back("!@#$%^&");
        strVec.print(cout);
        strVec1.print(cout);
    }
    _CrtDumpMemoryLeaks();
}

 

posted on 2016-01-04 21:20  峰入云  阅读(346)  评论(0编辑  收藏  举报

导航