《STL源码剖析》笔记:vector

vector 的数据安排以及操作方式,与array常常相似,两者的唯一差别在于空间运用的灵活性:array是静态空间,一旦配置了不能改变。vector动态空间,可以根据需要,自行扩充空间以容纳新元素。

vector的实现技术关键在于其对大小控制以及重新配置时的数据移动效率。因为重新申请内存,拷贝原数据,释放原vector是要花很长时间。所以在满载时,申请新空间的大小要在空间和时间上取出平衡。

vector结构很简单:

vector.png
template <typename T>
class Vector 
{
    ......
    typedef allocator<T> dataAlloc;
    private:
        T* _start;
        T* _finish;
        T* _end_of_storage;
}

迭代器

typedef T* iterator;
typedef const T *const_iterator

原生指针就可以充当迭代器。

添加元素

push_back(const T &value)
  • 有空间则直接用 construct 构造元素。
  • 没有空间则先重新分配新的内存,然后再把以前的元素拷贝之后,构造元素。也是因此,迭代器会失效
if (size() == capacity())
    reallocateAndCopy();
dataAlloc::construct(_finish++, value);
insert(iterator position, const size_type n, const T &value)
  • 备用空间足够
    2 种情况:
    • a: 插入点后现有元素个数 >= 新增元素个数
    • b: 插入点后现有元素个数 <= 新增元素个数
  • 备用空间不足
    • 第一步:将原vector [ _start, position )拷贝至新的 vector
    • 第二步:构造n个value
    • 第三步:将 [ position, _finish )元素也拷贝至新的 vector
    • 第四步:析构并释放原vector
/* 备用空间足够 */
if (_end_of_storage - _finish >= n) {
    size_type elems_after = _finish - position;
    iterator old_finish = _finish;
    if (elems_after > n) {
        /* 插入点后现有元素个数 >= x新增元素个数 */
        uninitialized_copy(position, old_finish - n, old_finish);
        _finish += n;
    } else {
        /* 插入点后现有元素个数 <= x新增元素个数 */
        uninitialied_fill_n(_finish, n - elems_after, value);
        _finish += n - elems_after;
        uninitialized_copy(position, old_finish, _finish);
        _finish += elems_after;
        fill(position, old_finish, value);
    }
}
/* 备用空间不够 */
else {
    size_type old_size = size();
    size_type len = old_size + max(old_size, n); // 新长度为旧长度的2倍,或者旧长度+新元素个数

    iterator new_start = dataAlloc::allocate(len); 
    iterator new_finish = new_start;

    try{
        /* 将原 vector[_start, position) 拷贝至新的vec */
        new_finish = uninitialized_copy(_start, position, new_start);
        /* 构造 n 个value */
        new_finish = uninitialied_fill_n(new_finish, n, value);
        /* 将 [position, _finish) 元素也拷贝过来 */
        new_finish = uninitialized_copy(position, _finish, new_finish);
    } catch(...) {
        destory(new_start, new_finish);
        dataAlloc::deallocate(new_start, len);
        throw;
    }
    /* 析构并释放原vector */
    destroyAndFree();

    _start = new_start;
    _finish = new_finish;
    _end_of_storage = _start + len;
}
备用空间足够,插入点后现有元素个数 <= 新增元素个数.png

修改容量

resize
  • n > capacity()需要重新分配内存空间,复制原size()元素,释放原资源,增加(n - size())个元素
  • size() < n <= capacity 不需要重新分配内存空间,增加(n - capacaity())个元素
  • n == size() 什么都不做
  • n < size() 需要析构(size() - n)个元素
void resize(size_type n, const T &value) {
    if (n > capacity()) {
        size_type addElementLength = n - size();
        /* 重新分配内存 */
        T *newStart = dataAlloc::allocate(n);
        T *newFinish = uninitialized_copy(begin(), end(), newStart);
        /* 拷贝元素 */
        newFinish = uninitialied_fill_n(newFinish, addElementLength, value);
        /* 销毁原内存 */
        destroyAndFree();
        /* 更新相关指针 */
        _start = newStart;
        _finish = newFinish;
        _end_of_storage = _start + n;
    } else if (n <= capacity() && n > size()) {
        size_type addElementLength = n - size();
        _finish = uninitialied_fill_n(end(), addElementLength, value);
    } else if (n < size()) {
        dataAlloc::destroy(begin() + n, end());
        _finish = _start + n;
    }
}
reserve
  • n > capacity() 重新分配内存空间,复制原size()元素,释放原资源。
void reserve(size_type n) {
    if (n > capacity()) {
        T *new_start = dataAlloc::allocate(n);
        T *new_finish = uninitialized_copy(begin(), end(), new_start);

        destroyAndFree();

        _start = new_start;
        _finish = new_finish;
        _end_of_storage = _start + n;
     }
}

删除元素

void pop_back()
void Vector<T>::pop_back() {
    dataAlloc::destroy(--_finish);
}
iterator erase(iterator first, iterator last)
size_type remove_element_counts = last - first;     // 要删除的个数

if (remove_element_counts > 0) {
    auto it = first;
    for (; last != _finish; last++, it++)
        *it = *last;
    dataAlloc::destroy(it, _finish);
    _finish = _finish - remove_element_counts;
}

return first;
iterator erase(iterator first, iterator last).png
iterator erase(iterator position)
return erase(position, position + 1);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • 标签(空格分隔): STL 运用STL,可以充分利用该库的设计,让我为简单而直接的问题设计出简单而直接的解决方案,...
    认真学计算机阅读 1,470评论 0 10
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,504评论 1 51
  • vector和string 所有的STL容器都很有用,但是相比于其他容器,vector和string更常用。本章从...
    lintong阅读 1,279评论 0 3
  • 哈哈红红火火恍恍惚惚
    习惯Mok阅读 142评论 0 0
  • 1、(芳蕊玫瑰--青春内雕)这个在福建已经做的非常火爆了、目前在市场上已经帮助了无数的女性。青春内雕项目能够让我们...
    游帅来也阅读 2,079评论 0 0