文章目录
- 前言
- 一、vector的介绍
- 二、vector的常用接口介绍
- 1.vector类对象的常见构造
- 2.vector iterator 的使用
- 3.vector类对象的容量操作
- 3.1 size、capacity 和 empty的使用
- 3.2 reserve的使用
- 3.3 resize的使用
- 4.vector类对象的访问(包含data:返回底层数组的指针)
- 5.vector类对象的修改操作
- 5.1 push_back、insert(插入数据)
- 5.2 pop_back、erase 和 clear(删除数据)
- 5.3 成员函数swap
- 6.vector类非成员函数
- 6.1 relational operators系列函数
- 6.2 非成员函数swap
前言
一、vector的介绍(包含vector类中typedef的部分类型别名介绍)
二、vector类的常用接口说明(vector类对象的 常见构造(重点)、容量操作、遍历操作 和 修改操作等接口,以及一些vector类非成员函数的接口)
一、vector的介绍
C++标准模板库中的容器vector是一个动态数组,能够自动管理内存,支持快速随机访问。 它的接口包括构造函数、大小和容量相关的操作、元素访问方法、修改容器的操作,还有迭代器相关的函数。
在C++标准库的 std::vector 中,allocator(内存分配器)是模板的第二个参数,通常可以忽略,使用默认的即可。但在需要特殊内存管理时,可以自定义allocator,不过这种情况相对少见。
默认内存分配器已足够高效,自定义内存分配器应仅在性能分析表明有必要时才会使用,所以后续介绍vector接口时,只会考虑大多数情况,忽略allocator(直接使用默认的)这个参数,简化vector的使用。
vector 类中typedef了很多类型别名,以下代码展示了一些常用的类型别名:
typedef T value_type;// 其中 T 是 vector 的第一个模板参数
typedef size_t size_type;
// size_t 是 C++ 标准库中定义的一个类型别名,它通常是一个无符号整数类型。其可能的定义方式如下:
// 64 位系统下: typedef unsigned long long size_t;
// 32 位系统下: typedef unsigned int size_t;
typedef T& reference;
typedef const T& const_reference;
typedef Allocator allocator_type;
二、vector的常用接口介绍
1.vector类对象的常见构造
忽略allocator相关参数后的简化接口:
(constructor)构造函数声明 | 接口说明 |
---|---|
vector() | 无参构造,默认构造空容器 |
vector( size_type n, const value_type& val =value_type() ) | 构造并初始化n个val |
template< class InputIterator > vector ( InputIterator first, InputIterator last ) | 使用迭代器进行初始化构造 |
vector (const vector& x) | 拷贝构造 |
vector ( initializer_list<value_type> il ) | 初始化列表构造(C++11新增,了解用法) |
示例一(无参构造,默认构造空容器):
vector( );
#include <vector>
using namespace std;int main()
{vector<int> app;// size和capacity均为0return 0;
}
示例二(构造并初始化n个val):
vector( size_t n, const T& val = T( ) );
#include <vector>
#include <string>
using namespace std;int main()
{vector<int> a1(5); // vector(size_t n, const int& val =int())vector<int*> a2(5); // vector(size_t n, const int*& val =int*())vector<int> a3(5, 10);vector<string> a4(5); // vector(size_t n, const string& val =string())vector<string> a5(5,"abcd");return 0;
}
补充:
(1)规定 int()、char() 等内置类型创建的匿名对象(不传参数时)默认为 0 ; int * ()、char * () 等默认为 nullptr
(2)string() 等自定义类型创建的匿名对象(不传参数时)会去调用对应的默认构造函数
示例三(使用迭代器进行初始化构造):
template< class InputIterator >
vector ( InputIterator first, InputIterator last );
#include <vector>
#include <list>
using namespace std;int main()
{list<int> lst = { 1, 2, 3, 4, 5 }; // 初始化列表的构造方式vector<int> vec1(lst.begin(), lst.end()); // list的迭代器是双向迭代器int arr[] = { 4, 5, 6, 7, 8, 9 };vector<int> vec2(arr + 2, arr + 5); // 指针作为随机访问迭代器vector<int> vec = { 10, 11, 12, 13, 14, 15 };vector<int> vec3(vec.begin() + 1, vec.end() - 2); // vector的迭代器是随机访问迭代器return 0;
}
补充知识(迭代器的种类):
在 C++ 中,迭代器(Iterator)是用于遍历容器(如
vector
、list
、map
等)中元素的对象,类似于指针的行为。根据功能强弱,迭代器分为以下 5 种类别,支持不同的操作:(1). 输入迭代器(Input Iterator)
- 功能:只能单向移动(向前),且只能读取元素(不可修改)。
- 支持的操作:
++
(前置/后置递增)、*
(解引用)、==
/!=
(比较)。- 典型应用:一次性遍历(如从文件流读取数据)。
- 示例:
istream_iterator
(用于输入流)。(2). 输出迭代器(Output Iterator)
- 功能:只能单向移动(向前),且只能写入元素(不可读取)。
- 支持的操作:
++
(前置/后置递增)、*
(解引用赋值)。- 典型应用:向容器或流中写入数据。
- 示例:
ostream_iterator
(用于输出流)。(3). 前向迭代器(Forward Iterator)
- 功能:继承自输入迭代器,支持多次读写和重复遍历。
- 支持的操作:所有输入迭代器的操作,且可以多次递增。
- 典型容器:单链表(如
forward_list
)、哈希表(如unordered_set
)。(4). 双向迭代器(Bidirectional Iterator)
- 功能:继承自前向迭代器,支持双向移动(向前和向后)。
- 支持的操作:所有前向迭代器的操作,新增
--
(前置/后置递减)。- 典型容器:双链表(如
list
)、关联容器(如set
、map
)。(5). 随机访问迭代器(Random Access Iterator)
- 功能:功能最强,支持直接跳跃访问任意位置。
- 支持的操作:所有双向迭代器的操作,新增:
+
/-
、+=
/-=
(跳跃多个位置)。[]
(下标访问)、比较大小(如<
,>
)。- 典型容器:连续内存容器(如
string
、vector
、deque
、数组)。
迭代器关系图示
输入迭代器 → 前向迭代器 → 双向迭代器 → 随机访问迭代器(功能由低到高)
输出迭代器(独立分支)
关键区别
- 随机访问迭代器效率最高(如
vector
的迭代器)。- 输入迭代器是等级最低的迭代器,所有更高级的迭代器(如前向、双向、随机访问迭代器)都兼容输入迭代器的功能。
- 双向迭代器仅支持逐步移动(如
list
)。- 算法需根据迭代器类型选择实现(如 算法库中的
sort
需要随机访问,而list
的双向迭代器不能满足sort
随机访问的要求,所以list
需用自己的sort
方法)。
示例四(拷贝构造):
vector (const vector& x);
#include <vector>
using namespace std;int main()
{vector<int> vec = { 10, 11, 12, 13, 14, 15 }; vector<int> vec1(vec); // 用vec拷贝构造vec1return 0;
}
示例五(初始化列表构造):
vector ( initializer_list< T > il );
#include <vector>
#include <string>
using namespace std;int main()
{vector<int> vec1{ 1, 2, 3 }; // 调用初始化列表构造vector对象时要使用花括号vector<string> vec2{ "hello", "world" };vector<int> vec3 = { 5, 6, 7 };return 0;
}
2.vector iterator 的使用
接口 | 功能 |
---|---|
begin | 获取第一个数据位置的iterator/const_iterator |
end | 获取最后一个数据的下一个位置的iterator/const_iterator |
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> s1 = { 1,3,5,7,9 };vector<int>::iterator it1 = s1.begin();// 普通vector对象调用 iterator begin();// 返回指向vector对象中第一个元素的普通迭代器,允许修改vector对象中的元素while (it1 != s1.end()){(*it1)++;cout << *it1 << ' ';++it1;}cout << endl;const vector<int> s2 = { 1,3,5,7,9 };vector<int>::const_iterator it2 = s2.begin();// const vector对象调用 const_iterator begin() const;// 返回指向const vector对象第一个元素的const迭代器,只允许读取const vector对象中的元素,不能修改while (it2 != s2.end()){cout << *it2 << ' ';++it2;}cout << endl;return 0;
}
3.vector类对象的容量操作
3.1 size、capacity 和 empty的使用
接口 | 功能 |
---|---|
size | 获取数据个数 |
capacity | 获取容量大小 |
empty | 判断是否为空 |
(1)size 和 capacity
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> vec1{ 1,2,3,4,5 };cout << "vec1的有效数据个数:" << vec1.size() << endl;cout << "vec1的容量:" << vec1.capacity() << endl;vector<int> vec2{ 6,6,6,6,6,6,6,6,6,6,6};cout << "vec2的有效数据个数:" << vec2.size() << endl;cout << "vec2的容量:" << vec2.capacity() << endl;return 0;
}
(2)empty
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> vec1{ 1,2,3,4,5 };cout << "vec1是否为空:" << vec1.empty() << endl;vector<int> vec2;cout << "vec2是否为空:" << vec2.empty() << endl;return 0;
}
3.2 reserve的使用
std::vector 类提供的 reserve() 成员函数,用于请求vector对象的容量调整。
注:这个函数不会改变vector对象的有效数据个数,也不会修改vector对象有效数据中的内容。
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,2,3,4,5,6,7,8,9 };cout << "v1的有效数据个数:" << v1.size() << endl;cout << "v1的容量:" << v1.capacity() << endl;v1.reserve(50);cout << "v1的有效数据个数:" << v1.size() << endl;cout << "v1的容量:" << v1.capacity() << endl;return 0;
}
我们一般只用reserve函数进行扩容,使用场景如下:在你预先知道vector对象将增长到某个大小时,可以使用reserve函数提前分配足够的空间,避免频繁扩容。
3.3 resize的使用
std::vector类提供的 resize() 成员函数,用于改变有效数据个数。
如果新的个数大于当前个数,会新增有效数据个数,新增元素初始化为 val;如果新的个数小于当前个数,减少有效数据个数。
示例一(新的个数大于当前个数,会新增有效数据个数,新增元素初始化为 val):
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,2,3 };cout << "v1的有效字符长度:" << v1.size() << endl;cout << "v1的容量:" << v1.capacity() << endl;v1.resize(5, 10);cout << "v1的有效字符长度:" << v1.size() << endl;cout << "v1的容量:" << v1.capacity() << endl;v1.resize(10, 100);cout << "v1的有效字符长度:" << v1.size() << endl;cout << "v1的容量:" << v1.capacity() << endl;return 0;
}
示例二(新的个数小于当前个数,减少有效数据个数):
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,2,3,4,5,6,7,8,9 };cout << "v1的有效字符长度:" << v1.size() << endl;cout << "v1的容量:" << v1.capacity() << endl;v1.resize(5);cout << '\n' << "v1的有效字符长度:" << v1.size() << endl;cout << "v1的容量:" << v1.capacity() << endl;return 0;
}
4.vector类对象的访问(包含data:返回底层数组的指针)
接口 | 功能 |
---|---|
operator[] | 返回n位置的数据(越界访问的情况是不确定的) |
at() | 返回n位置的数据(越界访问会抛异常) |
data() | 返回底层数组的指针(C++11) |
(1)operator[]
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{1,2,3,4,5,6,7,8,9};for (size_t i = 0; i < v1.size(); ++i){v1[i] += 1;cout << v1[i] << ' ';// 普通对象调用 int& operator[](size_t n); // 返回vector对象中指定位置数据的引用(int&),// 这意味着你可以通过返回的引用修改数据的内容。}cout << endl;const vector<int> v2{ 1,2,3,4,5,6,7,8,9 };for (size_t i = 0; i < v2.size(); ++i){cout << v2[i] << ' ';// const对象调用 const int& operator[](size_t n) const; // 返回vector对象中指定位置数据的常引用(const int&),// 这意味着你只能读取vector对象中的数据,而无法进行修改。}cout << endl;return 0;
}
(2)at( )
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{1,2,3,4,5,6,7,8,9};for (size_t i = 0; i < v1.size(); ++i){v1.at(i) += 1;cout << v1.at(i) << ' ';// 普通对象调用 int& at(size_t n); // 返回vector对象中指定位置数据的引用(int&),// 这意味着你可以通过返回的引用修改数据的内容。}cout << endl;const vector<int> v2{ 1,2,3,4,5,6,7,8,9 };for (size_t i = 0; i < v2.size(); ++i){cout << v2.at(i) << ' ';// const对象调用 const int& at(size_t n) const; // 返回vector对象中指定位置数据的常引用(const int&),// 这意味着你只能读取vector对象中的数据,而无法进行修改。}cout << endl;return 0;
}
(3)data( )
#include <vector>
#include <iostream>
using namespace std;int main()
{std::vector<int> myvector(5, 10);cout << "myvector contains:";for (unsigned i = 0; i < myvector.size(); ++i){cout << ' ' << myvector[i];}cout << '\n';int* p = myvector.data();*p = 20;++p;*p += 20;p[2] = 100;cout << "myvector contains:";for (unsigned i = 0; i < myvector.size(); ++i){ cout << ' ' << myvector[i];}cout << '\n';return 0;
}
5.vector类对象的修改操作
5.1 push_back、insert(插入数据)
接口 | 功能 |
---|---|
push_back | 在末尾插入一个元素 |
insert | 在迭代器 position 位置插入元素 |
(1)push_back
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,1,1,1,1,1,1,1 };for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';v1.push_back(100); // 尾插一个元素for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';return 0;
}
(2)insert
示例一(插入多个相同元素):
iterator insert(const_iterator pos, size_t count, const T& val);
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,1,1,1,1,1,1,1 };for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';v1.insert(v1.begin() + 5, 3, 10);for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';return 0;
}
示例二(插入范围元素):
template < class InputIterator >
iterator insert(const_iterator pos, InputIterator first, InputIterator last);
#include <vector>
#include <list>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,1,1,1,1,1,1,1 };for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';list<int> lst{ 10,11,12,13,14,15 };v1.insert(v1.begin() + 5, lst.begin(), lst.end()); // list的迭代器是双向迭代器for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';return 0;
}
示例三(插入初始化列表):
iterator insert(const_iterator pos, initializer_list< T > il);
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,1,1,1,1,1,1,1 };for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';v1.insert(v1.begin() + 5, { 9,5,2,7 }); // 插入初始化列表for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';return 0;
}
5.2 pop_back、erase 和 clear(删除数据)
接口 | 功能 |
---|---|
pop_back | 删除末尾元素 |
erase | 删除迭代器 pos 指向的元素 |
clear | 清空所有有效元素(不释放内存) |
(1)pop_back
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,2,3,4,5,6,7,8,9 };for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';v1.pop_back();for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';return 0;
}
(2)erase
示例一(删除单个元素):
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,2,3,4,5,6,7,8,9 };for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';v1.erase(v1.begin() + 5); // 删除第6个元素for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';return 0;
}
示例二(删除范围元素):
#include <vector>
#include <iostream>
using namespace std;int main()
{vector<int> v1{ 1,2,3,4,5,6,7,8,9 };for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';v1.erase(v1.begin() + 5, v1.end() - 1); //删除第6~8的元素for (unsigned i = 0; i < v1.size(); ++i){cout << ' ' << v1[i];}cout << '\n';return 0;
}
(3)clear
#include <vector>
using namespace std;int main()
{vector<int> v1{ 1,2,3,4,5,6,7,8,9 };v1.clear();return 0;
}
5.3 成员函数swap
swap成员函数是用于高效交换两个vector对象的内容的函数
#include <vector>
using namespace std;int main()
{vector<int> v1{ 1,2,3};vector<int> v2{ 10,20,30,40 };v1.swap(v2);return 0;
}
6.vector类非成员函数
6.1 relational operators系列函数
#include <vector>
using namespace std;int main()
{vector<int> v1{ 1,2,3 };vector<int> v2{ 1,2,3,4 };vector<int> v3{ 1,3,2 };// == 运算符:元素数量相同且对应元素相等bool b1 = (v1 == v2); // false(元素数量不同)// != 运算符:存在至少一个不相等元素bool b2 = (v1 != v3); // true(在第二个元素 2 != 3)// < 运算符:字典序比较,遇到第一个不同元素时判断bool b3 = (v1 < v2); // true(v1是v2的前缀)bool b4 = (v1 < v3); // true(在第二个元素 2 < 3)// > 运算符:字典序更大bool b5 = (v2 > v3); // false(在第二个元素 2 < 3)return 0;
}
核心原理:
字典序比较:
- 逐个元素对比,直到发现不相等的元素
- 若一个vector是另一个的前缀,较短的vector更小
- 元素必须支持
operator<
(自定义类型需重载)类型一致性:
- 只能比较相同类型的vector(
vector<int>
不能与vector<double>
比较)
6.2 非成员函数swap
std::vector的非成员函数swap专门用于交换两个同类型std::vector对象。它底层实际上调用了std::string的swap成员函数。
它在功能上与std::vector的swap成员函数完全一致,但其提供了更为通用的接口。
#include <vector>
using namespace std;int main()
{vector<int> v1{ 1,2,3};vector<int> v2{ 10,20,30,40 };swap(v1, v2); // 功能上与std::vector的swap成员函数完全一致,但其提供了更为通用的接口return 0;
}