C++ STL 空间适配器

目录:

  • 实现简单的Vector
  • 容器面临的问题
  • 空间适配器介绍
  • 带有空间适配器的Vector

 

一  实现简单Vector

#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<unistd.h>
#include<atomic>
using namespace std;
template<typename T>
class Vector {
  public:
  Vector(int size):cursize(0),maxsize(size) {
    vec = new T[size];
  }
  ~Vector() {
    delete []vec;
    vec = nullptr;
  }
  // 拷贝构造
  Vector(const Vector<T> &src):cursize(src.cursize),maxsize(src.maxsize) {
    
    vec = new T[src.maxsize];
    for(int i = 0;i < src.cursize;i++) {
      vec[i] = src.vec[i];
    }
  }
// 赋值构造函数 
  Vector<T> & operator = (const Vector<T> & src) {
    
    if(this == &src) {
      return *this;
    }
    delete []vec;
    vec = new T[src.maxsize];
    cursize = src.cursize;
    maxsize = src.maxsize;
    for(int i = 0; i< cursize; i++) {
      vec[i] = src.vec[i];
    }
    return *this;
  }

  // push_back;
  void push_back(const T &val) {
    
    if(cursize == maxsize) {
      resize();
    }
    vec[cursize++] = val;
  }
 // pop_back
 
  void pop_back() {
    if(cursize == 0) {
      return;
    }
    --cursize;
  }
  private:
    T *vec;
    atomic_int cursize;
    atomic_int maxsize;

    void resize() {
      if(maxsize == 0) {
        vec = new T[1];
        cursize = 0;
        maxsize = 1;
      }else {
        T * tmp = new T[2*maxsize];

        for(int i = 0; i < maxsize; i++) {
          tmp[i] = vec[i];
        }
      delete []vec;
      maxsize *=2;
      vec = tmp;
      }
    }
};



int main()
{
  Vector<int> v(10);

    cout<<endl;
    return 0;
}

二  容器存在的问题

  1.  定义容器Vector<int> vec(10) 时,我们希望底层开辟10个整型大小的空间,但是不但在开辟空间的同时,还构造了对象,浪费资源
  2. 调用pop_back时,我们希望是要删除最后一个元素,但是代码上并没有析构,如果这个对象还占有外部资源,那么就会造成内存泄露
  3. 当vec 的容器出作用域时,还会存在10次的析构,这些都是不合理的   

解决办法:

  1. 当定义容器的时候,我们只需要开辟内存,不用构造无用的对象
  2. 当pop_back 时不应该只是-- 操作,而应该调用对象的析构函数,是否释放额外的资源
  3. 当容器vec 析构时,应该把容器的有效对象进行析构,然后在释放整个容器的内存资源。

三  空间配置器

核心就是把容器的内存开辟和对象构造分开,对象析构和内存释放分开,容器适配器主要提供以下函数

空间配置器的函数功能
allocate 负责开辟内存
deallocate 负责释放内存
construct 负责在容器中构造对象
destroy 负责析构对象

自定义一个简单的空间适配器

#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<unistd.h>
using namespace std;

    
template<typename T>
class Myallocator {

  public:
    // 开辟内存空间
    T * allocator(size_t size) {
      return (T*) malloc(sizeof(T) * size);
    }
    // 释放内存空间
    void deallocate(void * ptr) {
      free(ptr);
    }

    // 负责对象构造
    void construct(T *ptr, const T &val) {
      new ((void*)ptr) T(val);  //  定位new 构造对象
    }
    
    void destory(T *ptr) {
      ptr->~T(); // 调用对应的析构函数
    }

};

四 实现一个带有空间配置器的Vector

#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<unistd.h>
#include<atomic>
using namespace std;

template<typename T>
class Myallocator {

  public:
    // 开辟内存空间
    T * allocator(size_t size) {
      return (T*) malloc(sizeof(T) * size);
    }
    // 释放内存空间
    void deallocate(void * ptr) {
      free(ptr);
    }

    // 负责对象构造
    void construct(T *ptr, const T &val) {
      new ((void*)ptr) T(val);  //  定位new 构造对象
    }
    
    void destory(T *ptr) {
      ptr->~T(); // 调用对应的析构函数
    }

};
template<typename T ,typename allocator = Myallocator<T>>
class Vector {
  public:
  Vector(int size,const allocator &alloc = allocator()):cursize(0),maxsize(size),myallocator(alloc) {
    vec = myallocator.allocator(size);
  }
  ~Vector() {
    for(int i =0; i< cursize; i++) {
      myallocator.destory(vec+i);
    }
    myallocator.deallocate(vec);
    vec = nullptr;
  }
  // 拷贝构造
  Vector(const Vector<T> &src):cursize(src.cursize),maxsize(src.maxsize),myallocator(src.myallocator) {
    
    vec = myallocator.allocator(maxsize);
    for(int i = 0;i < src.cursize;i++) {
      myallocator.construct(vec+i,src.vec[i]);
    }
  }
// 赋值构造函数 
  Vector<T> & operator = (const Vector<T> & src) {
    
    if(this == &src) {
      return *this;
    }
    for (int i = 0; i < cursize; ++i) {
      myallocator.destory(vec+i);
        }
    myallocator.deallocate(vec);
    cursize = src.cursize;
    maxsize = src.maxsize;
    vec = myallocator.allocator(maxsize);
    for(int i = 0; i< cursize; i++) {
      myallocator.construct(vec+i,src.vec[i]);
    }
    return *this;
  }

  // push_back;
  void push_back(const T &val) {
    
    if(cursize == maxsize) {
      resize();
    }
    myallocator.construct(vec+cursize,val);
    cursize++;
  }
 // pop_back
 
  void pop_back() {
    if(cursize == 0) {
      return;
    }
    --cursize;
    myallocator.destory(vec+cursize);
  }
  private:
    T *vec;
    atomic_int cursize;
    atomic_int maxsize;
    allocator myallocator;

    void resize() {
      if(maxsize == 0) {
        vec = new T[1];
        cursize = 0;
        maxsize = 1;
      }else {
        T * tmp = myallocator.allocator(2*maxsize);

        for(int i = 0; i < maxsize; i++) {
          myallocator.construct(tmp+i,vec[i]);
        }
        for(int i =0; i < maxsize; i++) {
          myallocator.destory(vec+i);
        }
        myallocator.deallocate(vec);
      maxsize *=2;
      vec = tmp;
      }
    }
};



int main()
{
  Vector<int> v(10);

    cout<<endl;
    return 0;
}

这样就解决了上面遇到的问题,在allocator 还可以带一个内存池实现

posted @ 2020-08-31 15:43  睡觉lc  阅读(292)  评论(0编辑  收藏  举报