返回首页 - Notes - 2012

C++ vector 标准库


标准库头文件:#include <vector>,命名空间:using std::vector;


基本概述

vector 称为 容器,是同一种类型对象的集合,每个对象都有一个对应的整数索引值

vector 不是一种数据类型,而只是一个 类模板,可用来定义任意多种数据类型

vector 和传统数组最为相似,每个容器都需要使用尖括号指定存储类型:std::vector<int> num;

可以给 vector 指定初始值,如不指定则默认以数字 0 或空字符串等进行填充:std::vector<int> num(22);

对于没有默认构造函数的类类型,在初始化这种类型的 vector 对象时,必须提供初始值

也可以传递两个参数来指定默认的元素值,比如包含 101vectorstd::vector<int> num(10, 1);

虽然可以对给定元素个数的 vector 对象预先分配内存,但更有效的方法是先初始化一个空的 vector 对象,然后再动态增加元素

vector 可以在任意位置插入或删除元素,但仅当在末尾执行这些操作时才会有最高的效率

在定义 vectorvector 时,要注意把相连的两个尖括号分开,不然会被编译器当成右移操作符:std::vector<std::vector<int> > num;


常用操作

vector 对象常用操作

  1. empty():测试是否为空
  2. size():返回元素个数
  3. push_back(t):向 vector 对象末尾添加元素
  4. front():返回第一个元素
  5. back():返回最后一个元素
  6. at(2):返回特定位置的元素值,相比数组的方括号访问形式,at() 提供了额外的安全控制
  7. vet[2]:返回指定索引处的元素值
  8. ==!=<<=>>=:这些比较运算符对 vector 照样有效

string 类型类似,size() 的返回值类型不是普通的 int 型,而是 vector<T>::size_type,这个 T 随定义的不同而不同

需要注意的是,下标索引的方式只能用于读取和改变元素值,而不能用来添加新元素,也就是说,必须是已存在的元素才能用下标进行操作,这是和 Ruby 等动态语言不同的

如果对 vector 操作不存在的索引值,编译器并不会报错,这极容易导致安全隐患,所以一般情况下应该使用迭代器而不是下标


迭代器(iterator)

迭代器 是一个位置对象,可以指向序列中的一个元素,至于这个序列是什么数据类型,迭代器 并不关心,迭代器 适用于所有容器

迭代器可以自加以实现向后移动一个元素,同样也可以自减向前移动一个元素,还可以一次移动多个:++iter--iteriter+=2

操作符 * 返回迭代器指向的值:*iter

使用 vector<int>::iterator 定义的迭代器既可读也可写,而使用 vector<int>::const_iterator 定义的迭代器只可读不可写

const_iterator 既可用于 const vector 也可用于非 const vector,而 iterator 只能用于非 const vector

相等性测试、加减等操作对 迭代器 也是适用的:iter1 == iter2iter1 != iter2iter1 - iter2

迭代器相加减的值有两种数据类型:size_typedifference_type

如果序列为空,将有 iter.begin() == iter.end(),更好的做法是使用迭代器的 empty() 函数

使用 迭代器 代替下标的优点:

  1. 使代码可以用于其他种类的容器(比如链表),即使它们没有 at() 成员函数
  2. 更有利于优化器产生高性能的代码
  3. 犯错的机会会更少,比如缓存溢出
  4. 代码更容易阅读,尤其对于有经验的 C++ 程序员

定位 vector 的中间元素:vector<int>::iterator mid = vct.begin() + vct.size()/2

任何改变 vector 长度的操作都会使已有 迭代器 失效,必须重新定义新的迭代器

以下两段代码等价:

// 代码1:使用下标
for(vector<string>::size_type ix(0); vct.size() != ix; ++ix){
    vct[ix] = "*";
    std::cout << vct[ix] << std::endl;
}

// 代码2:使用迭代器
for(vector<string>::iterator iter = vct.begin(); vct.end() != iter; ++iter){
    *iter = "*";
    std::cout << *iter << std::endl;
}

可以将 vector 看成是放宽了限制的 数组,而 iterator 则是更易于使用的 指针


date : 2012-02-19、2012-04-02、2012-04-03