STL的vector简化实现

本质

vector说到底就是一个动态数组,我们需要做的就是管理动态数组的内存,和元素的增加,删除,移动等。

template <typename T>
class vector {
public:
    typedef T* iterator;
    typedef T& reference;
protected:
    iterator start;          //第一个元素
    iterator finish;         //最后一个元素的后面一位
    iterator end_of_storage; //capacity的位置
public:
    ...
};

构造函数

实现很简单,就是创建一个动态数组,然后将iterator赋值好就行。

public:
  vector() : start(0), finish(0), end_of_storage(0) {};
  vector(unsigned n, const T& value) { init(n, value); }
  explicit vector(unsigned n) { init(n, T()); }

这里我使用了辅助初始化的函数init(其他函数也要用),其实现如下:

private:
void init(unsigned n, const T& value) {
    assert(n > 0);
    start = new T[n];
    finish = start + n;
    end_of_storage = finish;
    for(int i = 0; i < n; i++) {
        start[i] = value;
    }
}

析构函数

主要就是进行内存释放,指针赋空值。

~vector() { destory(); }

这里用到了辅助函数(其他函数也要用),实现如下:

private:
void destory() {
  delete[] start;
  start = finish = end_of_storage = nullptr;
}

assign

先判断当前容量是否足够,不足则先分配两倍的容量,然后再赋值。

void assign(unsigned num, const T& value) {
  while(num > capacity()) {
    extendDouble();
  }
  for(int i = 0; i < num; i++) {
    start[i] = value;
  }
}
void assign(iterator first, iterator last) {
  unsigned num = (unsigned)(last - first);
  while(num > capacity()) {
    extendDouble();
  }
  for(int i = 0; i < num; i++) {
    start[i] = first[i];
  }
}

这里用到辅助函数extendDouble来分配两倍的容量,实现如下:

void extendDouble() {
  //确定两倍容量的值
  unsigned newCapacity = capacity() * 2;
  if(newCapacity == 0) newCapacity = 1;
  //将旧值放到新数组中
  T* newMen = new T[newCapacity];
  unsigned oldSize = size();
  for(int i = 0; i < oldSize; i++) {
    newMen[i] = start[i];
  }
  //施放旧数组,赋值为新数组
  destory();
  start = newMen;
  finish = start + oldSize;
  end_of_storage = start + newCapacity;
}

back

reference back() { return start[size()-1]; }

begin

iterator begin() { return start; }

capacity

unsigned capacity() const {
    return (unsigned)(end_of_storage - start);
}

clear

void clear() { finish = start; }

empty

bool empty() const { return size() == 0; }

end

iterator end() { return finish; }

erase

对于删除操作,主要就是要将被删除元素后面的元素向前移动。

iterator erase(iterator pos) {
    assert(pos < finish);
    //将之后的元素向前移动
    unsigned delta = (unsigned)(pos - start);
    for(int i = delta; i < size()-1; i++)
        start[i] = start[i+1];
    finish--;
    return pos;
}
iterator erase(iterator first, iterator last) {
    assert(last > first && last < finish);

    unsigned firstIndex = (unsigned)(first - start);
    unsigned lastIndex = (unsigned)(last - start);
    for(int i = firstIndex, m = lastIndex; m < size(); i++, m++)
        start[i] = start[m];
    finish -= (unsigned)(last - first);
    return first;
}

从这里可以看出,被删除元素后面的iterator都失效,而前面的iterator则依然有效。

front

reference front() { return start[0]; }

insert

insert实现复杂一点,需要先分配好足够的容量,然后将插入点后的元素全部移动n个单位,最后将n个值依次从插入点开始赋值。

void insert(iterator pos, unsigned n, const T& value) {
    unsigned posIndex = (unsigned)(pos - start);
    unsigned newSize = size() + n;
    //分配好需要的容量
    while(newSize > capacity())
        extendDouble();

    pos = start + posIndex;
    unsigned numNeedMove = (unsigned)(finish - pos);
    //将插入点后面的元素先放到一个临时数组存起来
    T* temp = new T[numNeedMove];
    for(int i = 0; i < numNeedMove; i++) {
        temp[i] = pos[i];
    }
    //将n个值依次从插入点开始赋值
    for(int i = 0; i < n; i++) {
        pos[i] = value;
    }
    //将插入点后的元素重新放回到数组中
    for(int i = n; i < n+numNeedMove; i++) {
        pos[i] = temp[i-n];
    }

    finish = start + newSize;
    delete temp;
    temp = nullptr;
}

void insert(iterator pos, const T& value) {
    insert(pos, 1, value);
}

void insert(iterator pos, iterator first, iterator last) {
    unsigned n = (unsigned)(last - first);
    unsigned posIndex = (unsigned)(pos - start);
    unsigned newSize = size() + n;
    while(newSize > capacity())
        extendDouble();

    pos = start + posIndex;
    unsigned numNeedMove = (unsigned)(finish - pos);
    T* temp = new T[numNeedMove];
    for(int i = 0; i < numNeedMove; i++) {
        temp[i] = pos[i];
    }

    for(int i = 0; i < n; i++) {
        pos[i] = first[i];
    }
    for(int i = n; i < n+numNeedMove; i++) {
        pos[i] = temp[i-n];
    }

    finish = start + newSize;
    delete temp;
    temp = nullptr;
}

pop_back

void pop_back() {
    if(empty()) return;
    finish--;
}

push_back

void push_back(const T& value) {
    //容量足够
    if(finish != end_of_storage) {
        start[size()] = value;
        finish++;
    }
    //容量不足
    else {
        unsigned oldSize = size();
        extendDouble();
        start[oldSize] = value;
    }
}

reserve

void reserve(unsigned n) {
        if(n <= capacity()) return;

        unsigned oldSize = size();
        T* newOne = new T[n];
        for(int i = 0; i < size(); i++) {
            newOne[i] = start[i];
        }

        destory();
        start = newOne;
        finish = start + oldSize;
        end_of_storage = start + n;
    }

resize

void resize(unsigned s, const T& value) {
    if(s < size())
        erase(begin() + s, end());
    else
        insert(end(), s - size(), value);
}
void resize(unsigned s) { resize(s, T()); }

C++STL -- vector实现的更多相关文章

  1. C++ STL vector容器学习

    STL(Standard Template Library)标准模板库是C++最重要的组成部分,它提供了一组表示容器.迭代器.函数对象和算法的模板.其中容器是存储类型相同的数据的结构(如vector, ...

  2. STL vector

    STL vector vector是线性容器,它的元素严格的按照线性序列排序,和动态数组很相似,和数组一样,它的元素存储在一块连续的存储空间中,这也意味着我们不仅可以使用迭代器(iterator)访问 ...

  3. STL vector用法介绍

    STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和f ...

  4. STL vector+sort排序和multiset/multimap排序比较

    由 www.169it.com 搜集整理 在C++的STL库中,要实现排序可以通过将所有元素保存到vector中,然后通过sort算法来排序,也可以通过multimap实现在插入元素的时候进行排序.在 ...

  5. STL vector 用法介绍

    介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  6. STL vector使用方法介绍

    介绍 这篇文章的目的是为了介绍std::vector,怎样恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  7. stl——vector详解

    stl——vector详解 stl——vector是应用最广泛的一种容器,类似于array,都将数据存储于连续空间中,支持随机访问.相对于array,vector对空间应用十分方便.高效,迭代器使ve ...

  8. C++STL vector详解(杂谈)

    介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和for_each()中的使用.通 ...

  9. C++ stl vector介绍

    转自: STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if ...

  10. 浅谈C++ STL vector 容器

    浅谈C++ STL vector 容器 本篇随笔简单介绍一下\(C++STL\)中\(vector\)容器的使用方法和常见的使用技巧.\(vector\)容器是\(C++STL\)的一种比较基本的容器 ...

随机推荐

  1. 《CMake实践》笔记三:构建静态库(.a) 与 动态库(.so) 及 如何使用外部共享库和头文件

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  2. Swift3.0P1 语法指南——类和结构体

    原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...

  3. java8

    1:Scanner的使用(了解) (1)在JDK5以后出现的用于键盘录入数据的类. (2)构造方法: A:讲解了System.in这个东西. 它其实是标准的输入流,对应于键盘录入 B:构造方法 Inp ...

  4. vim技巧

    (三)多窗口操作 改变高度:res +n(增加n行的高度)n ctrlw  +/-改变宽度:vertical res +n(增加n列的宽度)n ctrl w >/< (一)缩进 vim提供 ...

  5. 移动端web开发技巧

    META相关 1. 添加到主屏后的标题(IOS)

  6. 使用原生ajax访问后台数据并将其展现在前端页面中(小菜鸟自己整理玩的,大神勿喷)

    首先你要有php的环境,关于php环境的搭建,php本地站点的搭建,此处不再重复请看这里:http://www.cnblogs.com/Gabriel-Wei/p/5950465.html我们把wam ...

  7. CDN -- 集合

    weui https://cdnjs.cloudflare.com/ajax/libs/weui/0.4.3/style/weui.min.css 百度静态资源库 http://cdn.code.ba ...

  8. R平方

    参考其他网页 通常R2越大越好,但看到亦在后面标上P值,这两者之间有何联系? R2和p值没有必然联系.就像你做线性分析和(单因素或多因素)方差分析一样,若A和K线性相关,也有可能A对K么有显著性影响一 ...

  9. C++ explicit关键字详解

    本文系转载,原文链接:http://www.cnblogs.com/ymy124/p/3632634.html 首先, C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用 ...

  10. tp框架之查询

    //数据访问        //造模型对象        $nation = D("Nation");                //查询        //$a = $nat ...