C++ vector 全面解析:从基础用法到深度剖析
C++ vector 是 STL 中最常用的动态数组容器,支持随机访问和自动扩容。详细讲解了 vector 的构造方法、迭代器使用规则、空间管理(size/capacity)、元素增删查改操作以及底层内存模拟实现。同时结合经典算法题目(如异或求唯一数、电话号码组合等)展示了 vector 在实际开发中的应用技巧及注意事项,包括迭代器失效处理、边界检查机制及深拷贝浅拷贝区别。

C++ vector 是 STL 中最常用的动态数组容器,支持随机访问和自动扩容。详细讲解了 vector 的构造方法、迭代器使用规则、空间管理(size/capacity)、元素增删查改操作以及底层内存模拟实现。同时结合经典算法题目(如异或求唯一数、电话号码组合等)展示了 vector 在实际开发中的应用技巧及注意事项,包括迭代器失效处理、边界检查机制及深拷贝浅拷贝区别。

在 C++ 标准模板库(STL)中,vector 是最常用也最灵活的容器之一。它作为动态数组,既保留了数组随机访问的高效性,又具备动态扩容的灵活性,在实际开发中有着广泛的应用。
本文将从 vector 的构造方法入手,逐步深入到迭代器使用、空间管理、元素操作等核心知识点,讲解各种 API 的用法细节,并通过模拟实现代码帮助读者理解其底层工作原理。针对 vector 使用中常见的迭代器失效、边界访问等问题进行详细说明,并结合典型算法题目展示 vector 在实际场景中的应用。
vector 支持多种构造方式,例如指定初始大小和值,或通过迭代器区间初始化。
vector<int> v1(10, 1);
vector<int> v3(v1.begin(), v1.end());
对于嵌套 vector,需注意 resize 时的层级关系:
vector<vector<int>> vv;
vv.resize(n);
for(auto& row : vv) row.resize(m);
注意:vector 的迭代器不一定是原生指针;反向迭代器 ++ 和迭代器 ++ 的移动方向相反;范围 for 循环配合反向迭代器可倒序遍历。
注意:使用 [] 访问时依据 size 判断越界。若 capacity 为 10 而 size 为 1,访问索引 9 会报错。
注意:vector 本身没有 find 成员函数,但可使用 std::find 算法查找。区间操作通常遵循左闭右开原则。
namespace renshen {
template<class T>
class vector {
public:
typedef T* iterator;
typedef const T* const_iterator;
iterator begin() { return _start; }
iterator end() { return _finish; }
const_iterator begin() const { return _start; }
const_iterator end() const { return _finish; }
vector(size_t n, const T& val = T())
: _start(nullptr), _finish(nullptr), _endofstorage(nullptr) {
resize(n, val);
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
: _start(nullptr), _finish(nullptr), _endofstorage(nullptr) {
while(first != last) {
push_back(*first);
++first;
}
}
vector() : _start(nullptr), _finish(nullptr), _endofstorage(nullptr) {}
vector(const vector<T>& v)
: _start(nullptr), _finish(), _endofstorage() {
_start = T[v.()];
( i = ; i < v.(); i++) {
_start[i] = v._start[i];
}
_finish = _start + v.();
_endofstorage = _start + v.();
}
{
std::(_start, v._start);
std::(_finish, v._finish);
std::(_endofstorage, v._endofstorage);
}
vector<T>& =(vector<T> v) {
(v);
*;
}
~() {
(_start) {
[] _start;
_start = _finish = _endofstorage = ;
}
}
{
(n > ()) {
sz = ();
T* tmp = T[n];
(_start) {
( i = ; i < sz; i++) {
tmp[i] = _start[i];
}
[] _start;
}
_start = tmp;
_finish = _start + sz;
_endofstorage = _start + n;
}
}
{
(n < ()) {
_finish = _start + n;
} {
(n);
(_finish != _start + n) {
*_finish = val;
++_finish;
}
}
}
{
((), x);
}
{
(--());
}
{ _endofstorage - _start; }
{ _finish - _start; }
T& []( pos) {
(pos < ());
_start[pos];
}
T& []( pos) {
(pos < ());
_start[pos];
}
{
(pos >= _start && pos <= _finish);
(_finish == _endofstorage) {
len = pos - _start;
newcapacity = () == ? : () * ;
(newcapacity);
pos = _start + len;
}
iterator end = _finish - ;
(end >= pos) {
*(end + ) = *end;
--end;
}
*pos = x;
++_finish;
pos;
}
{
(pos >= _start && pos < _finish);
iterator it = pos + ;
(it != _finish) {
*(it - ) = *it;
++it;
}
--_finish;
pos;
}
:
iterator _start;
iterator _finish;
iterator _endofstorage;
};
{
( e : v) {
cout << e << ;
}
cout << endl;
}
}
vector v(10, 1);:编译器调用 size_t 构造函数,因为第二个参数 1 匹配 val 类型,且 10 默认为 int 但会被隐式转换为 size_t。vector v1(10, "1111");:调用 size_t 构造函数。int j = int(); 等价于 int j = 0;。利用异或运算性质(相同为 0,不同为 1,符合分配律),对数组所有元素异或,结果即为只出现一次的数字。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int e = 0;
for(int i = 0; i < nums.size(); i++) {
e = e ^ nums[i];
}
return e;
}
};
在 Debug 模式下,std::vector::at 总是做边界检查,而 operator[] 不做边界检查。两者行为差异需根据需求选择。
int main() {
int ar[] = {1,2,3,4,5,6,7,8,9,10};
int n = sizeof(ar)/sizeof(int);
vector<int> v(ar, ar+n);
cout << v.size() << ":" << v.capacity() << endl; // 10:10
v.reserve(100);
v.resize(20);
cout << v.size() << ":" << v.capacity() << endl; // 20:100
v.reserve(50);
v.resize(5);
cout << v.size() << ":" << v.capacity() << endl; // 5:100
return 0;
}
使用 DFS 回溯法,注意 vector 为空时直接返回空 vector 而非空字符串,传递 vector 引用避免重复拷贝。
class Solution {
public:
string qq[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
void dfs(vector<string>& f, int level, string p, string digits) {
if(level == digits.size()) {
f.push_back(p);
return;
}
for(int i = 0; i < qq[digits[level]-'0'].size(); i++) {
dfs(f, level+1, p+qq[digits[level]-'0'][i], digits);
}
}
vector<string> letterCombinations(string digits) {
vector<string> a;
if(digits == "") return a;
dfs(a, 0, "", digits);
return a;
}
};
排序后取中间元素即可。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int>& numbers) {
sort(numbers.begin(), numbers.end());
return numbers[numbers.size()/2];
}
};
统计二进制位出现次数,对 3 取模,剩余即为目标数字的二进制位。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0;
for(int i = 0; i < 32; ++i) {
int total = 0;
for(int e : nums) {
total += ((e >> i) & 1);
}
if(total % 3) {
ret |= (1 << i);
}
}
return ret;
}
};
全部异或得到 sum,找出最低位 1,将数组分为两组分别异或。
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
long long int sum = 0;
for(auto e : nums) {
sum = sum ^ e;
}
long long int lowbit = sum & (-sum);
int num1 = 0, num2 = 0;
for(auto e : nums) {
if((lowbit & e) == 0) num1 ^= e;
else num2 ^= e;
}
return {num1, num2};
}
};

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online