vector
vector<T>
容器是包含 T 类型元素的序列容器,和 array<T,N>
容器相似,不同的是 vector<T>
容器的大小可以自动增长,从而可以包含任意数量的元素;因此类型参数 T 不再需要模板参数 N。只要元素个数超出 vector 当前容量,就会自动分配更多的空间。只能在容器尾部高效地删除或添加元素。
vector<T>
容器可以方便、灵活地代替数组。在大多数时候,都可以用 vector<T>
代替数组存放元素。只要能够意识到,vector<T>
在扩展容量,以 及在序列内部删除或添加元素时会产生一些开销;但大多数情况下,代码不会明显变慢。 为了使用 vector<T>
容器模板,需要在代码中包含头文件 vector。
创建
- 容器中没有元素,所以没有分配空间,当添加第一个数据项时,会自动分配内存:
因为容器中没有元素,所以没有分配空间,当添加第一个数据项时,会自动分配内存。可以像下面这样通过调用 reserve()
来增加容器的容量:
如果当前的容量已经大于或等于 20 个元素,那么这条语句什么也不做。注意,调用 reserve()
并不会生成任何元素。values 容器这时仍然没有任何元素,直到添加了 20 个元素后,才会分配更多的内存。调用 reserve()
并不会影响现有的元素。
如果通过调用 reserve()
来增加内存,任何现有的迭代器,例如开始迭代器和结束迭代器,都会失效,所以需要重新生成它们。这是因为,为了增加容器的容量,vector<T>
容器的元素可能已经被复制或移到了新的内存地址。
- 创建 vector 容器的另一种方式是使用初始化列表来指定初始值以及元素个数:
| |
| vector<int> values{1, 2, 3}; |
- 使用初始元素个数来生成 vector 容器:
- 指定一个其他值作为默认值:
| |
| vector<int> values(10, 7); |
- 用元素类型相同的容器来初始化
vector<T>
容器
| #include <vector> |
| #include <array> |
| #include <iostream> |
| #include <string> |
| |
| using namespace std; |
| |
| int main() { |
| array<string, 5> words{"one", "two", "three", "four", "five"}; |
| |
| vector<string> words_copy{begin(words), end(words)}; |
| |
| |
| vector<string> words_copy2 |
| {make_move_iterator(begin(words)), make_move_iterator(end(words))}; |
| |
| } |
容量和大小
vector 的容量大小,是指在不分配更多内存的情况下可以保存的最多元素个数,这时 可能有 20 个元素,也可能没有。vector 的大小是它实际所包含的元素个数,也就是有值的元素的个数。

| #include <vector> |
| #include <iostream> |
| |
| using namespace std; |
| |
| int main() { |
| vector<int> values{1, 2, 3}; |
| cout << "大小:" << values.size() << endl; |
| cout << "容量:" << values.capacity() << endl; |
| |
| values.resize(5); |
| |
| values.resize(7, 99); |
| |
| |
| |
| values.resize(6); |
| |
| |
| for (int i: values) { |
| cout << i << " "; |
| } |
| } |
访问
| #include <vector> |
| #include <iostream> |
| |
| using namespace std; |
| |
| int main() { |
| vector<int> values{1, 2, 3}; |
| values[1] = 0; |
| |
| values.at(2) = 3; |
| |
| |
| cout << values.front() << endl; |
| |
| values.back() = 10; |
| |
| |
| |
| int *pInt = values.data(); |
| } |
迭代器
添加
| #include <vector> |
| #include <iostream> |
| |
| using namespace std; |
| |
| int main() { |
| vector<int> values{1, 2, 3}; |
| values.push_back(12); |
| |
| |
| values.emplace_back(13); |
| |
| |
| for (auto i: values) { |
| cout << i << " "; |
| } |
| } |
插入
通过使用成员函数 emplace(),可以在 vector 序列中插入新的元素。对象会在容器中直接生成,而不是先单独生成对象,然后再把它作为参数传入。
| #include <vector> |
| #include <iostream> |
| #include <string> |
| |
| using namespace std; |
| |
| int main() { |
| vector<string> words{"first", "second"}; |
| |
| |
| |
| auto iter = words.emplace(begin(words), 5, 'A'); |
| |
| words.emplace(++iter, "$$$$"); |
| |
| |
| for (const auto &i: words) { |
| cout << i << " "; |
| } |
| } |
| #include <vector> |
| #include <iostream> |
| #include <string> |
| |
| using namespace std; |
| |
| int main() { |
| vector<string> words{"one", "three", "eight"}; |
| |
| |
| auto iter = words.insert(++begin(words), "two"); |
| |
| |
| |
| |
| |
| |
| |
| |
| string more[]{"five", "six", "seven"}; |
| iter = words.insert(--end(words), begin(more), end(more)); |
| |
| |
| |
| iter = words.insert(end(words), "ten"); |
| |
| |
| |
| iter = words.insert(cend(words)-1, 2, "nine"); |
| |
| |
| |
| |
| |
| iter = words.insert(end(words), {string {"twelve"},string {"thirteen"}}); |
| |
| |
| for (const auto &i: words) { |
| cout << i << " "; |
| } |
| } |
所有不在 vector 尾部的插入点都会有开销,需要移动插入点后的所有元素,从而为新元素空出位置。当然,如果插入点后的元素个数超出了容量,容器会分配更多的内存,这会增加更多额外开销。
删除
pop_back()
、clear()
、shrink_to_fit()
:
| #include <vector> |
| #include <algorithm> |
| |
| using namespace std; |
| |
| int main() { |
| vector<int> data{1, 2, 3, 4, 5}; |
| |
| swap(*(begin(data) + 1), *(end(data) - 1)); |
| |
| |
| |
| data.pop_back(); |
| |
| |
| |
| data.clear(); |
| |
| |
| |
| data.push_back(111); |
| |
| data.shrink_to_fit(); |
| |
| } |
erase()
:
| #include <vector> |
| |
| using namespace std; |
| |
| int main() { |
| vector<int> data{1, 2, 3, 4, 5}; |
| |
| auto iter = data.erase(begin(data) + 1); |
| |
| |
| |
| |
| iter = data.erase(begin(data), begin(data) + 2); |
| } |
remove()
:
| #include <vector> |
| #include <algorithm> |
| #include <string> |
| |
| using namespace std; |
| |
| int main() { |
| vector<string> words{"one", "none", "some", "all", "none", "most", "many"}; |
| |
| auto iter = remove(begin(words), end(words), "none"); |
| |
| |
| |
| |
| words.erase(iter, end(words)); |
| } |
reserve()、resize() 区别
成员方法 |
功能 |
capacity() |
告诉我们当前 vector 容器总共可以容纳多少个元素。如果想知道当前 vector 容器有多少未被使用的存储空间,可以通过 capacity()-size() 得知。注意,如果 size() 和 capacity() 返回的值相同,则表明当前 vector 容器中没有可用存储空间了,这意味着,下一次向 vector 容器中添加新元素,将导致 vector 容器扩容。 |
size() |
告诉我们当前 vector 容器中已经存有多少个元素,但仅通过此方法,无法得知 vector 容器有多少存储空间。 |
reserve(n) |
强制 vector 容器的容量至少为 n。注意,如果 n 比当前 vector 容器的容量小,则该方法什么也不会做;反之如果 n 比当前 vector 容器的容量大,则 vector 容器就会扩容。 |
- vector 的
reserve
增加了 vector 的 capacity
,但是它的 size
没有改变。而 resize
改变了 vector 的 capacity
同时也增加了它的 size
。
reserve
是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用 push_back()
等函数。
resize
是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用 operator[]
操作符,或者用迭代器来引用元素对象。此时再调用 push_back()
函数,是加在这个新的空间后面的。
- 两个函数的参数形式也有区别的,
reserve
函数之后一个参数,即需要预留的容器的空间;resize
函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步