C++ vector容器详解
在 C++ 中,vector 容器定义在标准头文件
C++ 数组最大的优点就是可以使用下标随机访问数组元素。但其缺点也很明显,不仅需要时刻防备下标越界的危险,还要注意空间不足的情况。使用 vector 的初衷往往就是用来替换数组。
vector 同数组最大的区别在于其内存空间可以动态增长,即当需要更大的内存空间时,vector 可以自动增长,同时又不破坏原来的数据。
具体来讲,当 vector 发现其容量不够时,首先开辟一块儿新的空间,新空间要比原有的空间大,足可以容纳 vector 原有的元素以及新添加的元素,然后再把原有的元素和新添加的元素复制到新的内存空间中。
有关表示各个成员函数的语法格式,读者不需要死记硬背,需要时直接去查 C++ 标准库即可,这里不再过多赘述。
下面的 C++ 代码演示了表中部分成员函数的用法:
因此,vector 适用于在元素数量变化不大或者只需要增加元素的情况下,如果需要频繁地插入、删除元素,则应当考虑使用别的容器。
<vector>
中,其行为非常类似于数组,存储在其中的数据在内存中也是连续的,而且可以通过下标进行随机存取。C++ 数组最大的优点就是可以使用下标随机访问数组元素。但其缺点也很明显,不仅需要时刻防备下标越界的危险,还要注意空间不足的情况。使用 vector 的初衷往往就是用来替换数组。
vector 同数组最大的区别在于其内存空间可以动态增长,即当需要更大的内存空间时,vector 可以自动增长,同时又不破坏原来的数据。
具体来讲,当 vector 发现其容量不够时,首先开辟一块儿新的空间,新空间要比原有的空间大,足可以容纳 vector 原有的元素以及新添加的元素,然后再把原有的元素和新添加的元素复制到新的内存空间中。
vector容器的构造
本质上,vector 是一个模板类,它提供了多种构造函数,功能基本上都是设置 vector 容器的初始长度,以及初始化容器内各个元素的值。包括:// 默认构造函数,长度为 0 explicit vector (const allocator_type& alloc = allocator_type()); // 长度为 n,所有元素被默认初始化 explicit vector (size_type n); // 长度为 n,所有元素初始化为 val vector (size_type n, const value_type& val, const allocator_type& alloc = allocator_type()); // 使用迭代器 first 和 last 指定的范围内的元素来初始化 vector template <class InputIterator> vector (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()); // 拷贝构造函数,创建一个与 x 相同的新 vector 对象。 vector (const vector& x); vector (const vector& x, const allocator_type& alloc); // 移动构造函数,创建一个新的 vector 对象,并从 x 中“移动”数据,而不进行深度拷贝。 vector (vector&& x); vector (vector&& x, const allocator_type& alloc); // 初始化列表构造函数,使用给定的初始化列表 il 来初始化 vector。 vector (initializer_list<value_type> il, const allocator_type& alloc = allocator_type());下面是一个完整的 C++ 示例,演示了用各种构造函数来创建 vector 容器。
#include <iostream> #include <vector> #include <iterator> int main() { // 使用默认构造函数创建一个空 vector std::vector<int> vec1; // 创建一个大小为 5 的 vector,所有元素默认初始化(对于 int,这通常是0) std::vector<int> vec2(5); // 创建一个大小为 5 的 vector,所有元素初始化为 1 std::vector<int> vec3(5, 1); // 使用迭代器创建一个 vector int arr[] = {1, 2, 3, 4, 5}; std::vector<int> vec4(arr, arr + 5); // 使用拷贝构造函数创建一个新 vector std::vector<int> vec5(vec4); // 使用移动构造函数创建一个新 vector std::vector<int> vec6(std::move(vec5)); // 使用初始化列表创建一个 vector std::vector<int> vec7 = {1, 2, 3, 4, 5}; return 0; }
vector容器的使用
有关 vector 元素的操作,无非是增、删、改、查,可以借助 vector 模板类提供的成员函数来实现,如下表所示。函数成员 | 函数功能 |
---|---|
begin() | 返回指向容器中第一个元素的迭代器。 |
end() | 返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用。 |
rbegin() | 返回指向最后一个元素的迭代器。 |
rend() | 返回指向第一个元素所在位置前一个位置的迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
size() | 返回实际元素个数。 |
max_size() | 返回元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。 |
resize() | 改变实际元素的个数。 |
capacity() | 返回当前容量。 |
empty() | 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。 |
reserve() | 增加容器的容量。 |
shrink _to_fit() | 将内存减少到等于当前元素实际所使用的大小。 |
operator[ ] | 重载了 [ ] 运算符,可以向访问数组中元素那样,通过下标即可访问甚至修改 vector 容器中的元素。 |
at() | 使用经过边界检查的索引访问元素。 |
front() | 返回第一个元素的引用。 |
back() | 返回最后一个元素的引用。 |
data() | 返回指向容器中第一个元素的指针。 |
assign() | 用新元素替换原有内容。 |
push_back() | 在序列的尾部添加一个元素。 |
pop_back() | 移出序列尾部的元素。 |
insert() | 在指定的位置插入一个或多个元素。 |
erase() | 移出一个元素或一段元素。 |
clear() | 移出所有的元素,容器大小变为 0。 |
swap() | 交换两个容器的所有元素。 |
emplace() | 在指定的位置直接生成一个元素。 |
emplace_back() | 在序列尾部生成一个元素。 |
有关表示各个成员函数的语法格式,读者不需要死记硬背,需要时直接去查 C++ 标准库即可,这里不再过多赘述。
下面的 C++ 代码演示了表中部分成员函数的用法:
#include <iostream> #include <vector> using namespace std; int main() { //初始化一个空vector容量 vector<char>value; //向value容器中的尾部依次添加 S、T、L 字符 value.push_back('S'); value.push_back('T'); value.push_back('L'); //调用 size() 成员函数容器中的元素个数 printf("元素个数为:%d\n", value.size()); //使用迭代器遍历容器 for (auto i = value.begin(); i < value.end(); i++) { cout << *i << " "; } cout << endl; //向容器开头插入字符 value.insert(value.begin(), 'C'); cout << "首个元素为:" << value.at(0) << endl; return 0; }输出结果为:
元素个数为:3
S T L
首个元素为:C
完整实例
以下是一个 C++ 示例程序,演示了如何使用 std::vector 容器进行各种操作,包括初始化、添加元素、访问元素、遍历、以及删除元素。#include <iostream> #include <vector> int main() { // 1. 初始化:创建一个空的 vector 容器 std::vector<int> vec1; // 2. 初始化:使用列表初始化 std::vector<int> vec2 = {1, 2, 3, 4, 5}; // 3. 初始化:使用构造函数,创建一个包含 5 个元素为 0 的 vector std::vector<int> vec3(5, 0); // 4. 添加元素:使用 push_back() 在尾部添加元素 vec1.push_back(10); vec1.push_back(20); vec1.push_back(30); // 5. 访问元素:使用下标运算符 std::cout << "First element of vec2: " << vec2[0] << std::endl; // 6. 访问元素:使用 at() 函数 std::cout << "Second element of vec2: " << vec2.at(1) << std::endl; // 7. 遍历元素:使用范围 for 循环 std::cout << "Elements of vec1: "; for (const auto &elem : vec1) { std::cout << elem << ' '; } std::cout << std::endl; // 8. 遍历元素:使用迭代器 std::cout << "Elements of vec2: "; for (auto it = vec2.begin(); it != vec2.end(); ++it) { std::cout << *it << ' '; } std::cout << std::endl; // 9. 删除元素:使用 pop_back() 删除最后一个元素 vec1.pop_back(); // 10. 删除元素:使用 erase() 删除第一个元素 vec2.erase(vec2.begin()); // 11. 获取容器大小:使用 size() 函数 std::cout << "Size of vec3: " << vec3.size() << std::endl; return 0; }运行结果为:
First element of vec2: 1
Second element of vec2: 2
Elements of vec1: 10 20 30
Elements of vec2: 1 2 3 4 5
Size of vec3: 5
总结
vector 的内存空间是连续的,查找元素很快,可以像数组一样用下标进行访问,内存空间可以随需要增长。vector 的缺点也很明显,就是插入和删除元素较慢。因此,vector 适用于在元素数量变化不大或者只需要增加元素的情况下,如果需要频繁地插入、删除元素,则应当考虑使用别的容器。