前面介绍了STL对象的构造与析构以及内存的配置与释放,那具体的容器是怎么应用STL的空间配置器的呢?这篇先介绍STL的容器vector。

vector的数据成员

vector只有4个数据成员:3个迭代器、1个内存配置器。

STL会为每个容器都设置一个内存配置器的成员,这里的内存配置器就是前面介绍的STL空间配置器,使用了统一对外接口的类simple_alloc,即STL会为每个容器都定义一个simple_alloc类的类型成员,通过该类型成员来为容器分配内存。

vector的迭代器就是原始指针,只不过用了typedef将迭代器的类型变为了iterator,其实它就是T* 。vector的3个迭代器分别指向当前内存的起始地址(start)、最后一个数据的尾后地址(finish)、整个内存的最后地址(end_of_storage)。源码如下:

class vector
{
public:
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator;//vector迭代器就是一个原生指针
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef MiniSTL::reverse_iterator<iterator> reverse_iterator;
typedef MiniSTL::reverse_iterator<const_iterator> const_reverse_iterator;
typedef alloc allocator_type; allocator_type get_allocator() const { return allocator_type(); } private:
typedef simple_alloc<T, allocator_type> data_allocator;
iterator start;
iterator finish;
iterator end_of_storage;

vector对象的构造

vector有多种构造函数,但做的事情都一样,即先调用内存配置器去分配一块内存,然后对这块内存初始化,最后设置3个迭代器成员,让它们指向正确的位置。

以我们平常使用最多的vector构造方法,如:vector<int> vec(10); 为例,其对应的构造函数如下,下面还将该构造过程涉及到的函数一并列出:

构造函数vector(size_type n)调用fill_initializer函数,该函数会调用allocate_and_fill函数先去分配一块内存,然后进行初始化,由于这种构造方式未提供初始值,则按T类型的默认初始化进行初始化,然后剩下工作就是设置好start、finish、end_of_storage迭代器,工作便完成。

        void fill_initializer(size_type n, const T& value)
{
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
} iterator allocate_and_fill(size_type n, const T& value)
{
iterator result = data_allocator::allocate(n);
uninitialized_fill_n(result, n, value);
return result;
} public:
vector() : start(), finish(), end_of_storage() {}
explicit vector(size_type n) { fill_initializer(n, T()); }

vector空间的动态增长

当我们向vector进行push_back时,若原内存空间未满,那很好,直接在后面添加一个元素即可。若原内存空间已满,则不能直接在其后面添加了,因为谁也不知道原空间后面的内存到底是魔鬼还是天使。

所以,若原空间内存已满,继续往vector添加元素时,会先调用内存配置数据成员,分配一块新的内存,为了减少内存分配的次数,所以既然要分配了,那干脆就多分点,所以这块新内存的大小为原空间内存的2倍。

接着,将原内存上的数据拷贝到新内存中--->析构原内存空间中的对象--->释放原内存空间--->重新设置迭代器。

vector添加元素时,会导致内存空间的重新分配,所以会导致之前的迭代器都失效。

vector要是经常这样动态增长会导致程序效率下降,所以可以调用vector的reserve函数预先分配一大块指定大小的内存,以减少内存重分配次数。

对照下面源码分析。当finish和end_of_storage相等,则知道已经没有剩余空间了,push_back会调用insert_aux函数完成剩下全部工作。insert_aux函数调用allocate函数分配原空间2倍大小的新内存空间,调用uninitialized_copy函数将原内存中数据拷贝到新内存,接着调用destroy析构原空间中对象,调用deallocate()释放原内存空间,并重新设置start、finish、end_of_storage迭代器。如下:

push_back :

        void push_back(const T& val)
{
if (finish != end_of_storage)
{
construct(finish, val);
++finish;
}
else
insert_aux(end(), val);
}

insert_aux :

template<typename T>
void
vector<T>::insert_aux(iterator position, const T& x)
{
if (finish != end_of_storage) //还有备用空间
{
construct(finish, *(finish - ));
++finish;
T x_copy = x;
copy_backward(position, finish - , finish - );
*position = x_copy;
}
else
{
const size_type old_size = size();
const size_type len = old_size != ? * old_size : ; //2倍原空间大小
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start; try {
new_finish = uninitialized_copy(start, position, new_start);
construct(new_finish, x);
++new_finish;
new_finish = uninitialized_copy(position, finish, new_finish);
}
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
} destroy(begin(), end()); // 析构原内存空间的对象
deallocate(start, end_of_storage - start); // 释放原内存空间
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}

有关vector空间的动态增长的详细介绍可参考我的另一篇文章:http://www.cnblogs.com/zxiner/p/7197327.html

 

(全文完)

附:
一款简易版STL的实现,项目地址:https://github.com/zinx2016/MiniSTL/tree/master/MiniSTL

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. css因Mime类型不匹配而被忽略,怎么解决

    问题:在火狐.谷歌都可以正常显示出来,在别人的IE浏览器上也可以正常显示出来,但是在自己的ie浏览器就完全不能加载的熬样式了 控制台报告 SEC7113: CSS 因 Mime 类型不匹配而被忽略 答 ...

  2. loadrunner提高篇-结果分析实践

    分析图合并 一.分析图合并原理 选择view->merge graphs,弹出如图1所示对话框 图1(设置合并图) 1.选择要合并的图.选择一个要与当前活动图合并的图,注意这里只能选择X轴度量单 ...

  3. C#程序遍历数组A中所有元素

    ] { "a1","a2","a3","a4","a5"}; //第一种方法 ; i < A. ...

  4. NodeMCU透传数据到TcpServer和Yeelink平台

    准备工作 1. NodeMCU  LUA ESP8266 CP2102  WIFI Internet Development Board,仔细看背面可以看出自带cp2102模块,可以通过普通的手机充电 ...

  5. Pycon 2017: Python可视化库大全

    本文首发于微信公众号“Python数据之道” 前言 本文主要摘录自 pycon 2017大会的一个演讲,同时结合自己的一些理解. pycon 2017的相关演讲主题是“The Python Visua ...

  6. HTML中那些不常用标签

    先思考一个问题:为什么H5里面又多了那么多看似没用的标签? 我们知道,<div>能干百分之99的标签能干的事,而标签的主要作用是用来包裹内容,只要把基本内容都包含进去不就好了??胡闹!不带 ...

  7. 【转载】图文详解 IntelliJ IDEA 15 创建普通 Java Web 项目

    第 1 部分:新建一个 Java Web Application 项目 File -> New -> Project-,请选择 Java EE 这个模块下的 Web Application ...

  8. H5拖拽 构造拖拽及缩放 pdf展示

    前言: 协助项目需要实现一个签名的功能. 功能说明:1.有文本签名和头像签名.2.头像签名需要实现可拖拽功能.3.需要展示的是pdf的文件并需要获取签名位于pdf文件的相对位置. 功能一:实现拖拽 思 ...

  9. 【解决】VS2013 + Qt 5.7(5.6适用)使用QSqlDatabase出现“无法解析的外部符号"错误

    原始日期: 2016-08-03 22:09  错误如下: error LNK2019: 无法解析的外部符号 "__declspec(dllimport) public: __thiscal ...

  10. 关于MATLAB处理大数据坐标文件

    原先有3000条测试数据,MATLAB表现出来强大的数据处理能力,十几秒就可以把数据分类.分装并储存,这次共有10万条坐标数据,MATLAB明显后劲不足,显示内存不足 自我认识:以前MATLAB数据处 ...