std::vector
是 C++ 标准模板库 (STL) 中的一个动态数组容器。
std::vector 初始化
#include <array>
#include <iostream>
#include <vector>
int main() {
// 默认初始化 创建一个空的 std::vector。
std::vector<int> vec1;
// 指定大小的初始化 创建一个包含10个元素的vector,元素值为0(对于int类型)
std::vector<int> vec2(10);
// 指定大小和初始值的初始化 创建一个包含10个元素的vector,元素值均为5
std::vector<int> vec3(10, 5);
// 列表初始化 使用花括号 {} 直接初始化 std::vector。
std::vector<int> vec4 = {1, 2, 3, 4, 5};
// 使用迭代器范围初始化 从另一个容器或 std::vector 中复制元素。
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> vec5(source.begin(), source.end());
// 使用 std::array 初始化 从 std::array 初始化 std::vector。
std::array<int, 5> arr = {1, 2, 3, 4, 5};
std::vector<int> vec6(arr.begin(), arr.end());
// 从指针范围初始化 通过指针初始化 std::vector。
int arr2[] = {1, 2, 3, 4, 5};
std::vector<int> vec7(arr2, arr2 + 5);
return 0;
}
插入元素
vector::push_back
和 vector::emplace_back
都是 C++ 标准库中 std::vector
提供的成员函数,用于在向量末尾添加元素。它们之间的主要区别在于处理对象的方式和效率:
push_back
push_back
会将一个已经存在的对象复制(或移动)到向量的末尾。这意味着需要调用对象的拷贝构造函数或移动构造函数。如果对象的拷贝或移动操作比较昂贵,那么 push_back
的性能可能会受到影响。
示例:
std::vector<std::string> vec;
std::string str = "Hello, World!";
vec.push_back(str); // 将str的副本添加到vec的末尾
emplace_back
emplace_back
直接在向量的末尾构造对象,避免了不必要的拷贝或移动。这通常会带来性能上的提升,特别是对于复杂对象。
示例:
std::vector<std::string> vec;
vec.emplace_back("Hello, World!"); // 直接在vec的末尾构造一个std::string对象
选择 push_back 还是 emplace_back
- 如果你已经有一个现成的对象,并且只是想将它添加到向量末尾,使用
push_back
。 - 如果你希望直接在向量末尾构造一个对象,避免不必要的拷贝或移动,使用
emplace_back
。
示例代码对比
#include <iostream>
#include <vector>
#include <string>
struct MyClass {
MyClass(int x, double y) {
std::cout << "Constructed with (" << x << ", " << y << ")\n";
}
MyClass(const MyClass& other) {
std::cout << "Copy constructed\n";
}
MyClass(MyClass&& other) noexcept {
std::cout << "Move constructed\n";
}
};
int main() {
std::vector<MyClass> vec;
// 使用 push_back
MyClass obj(10, 20.5);
vec.push_back(obj); // 会调用一次拷贝构造函数
// 使用 emplace_back
vec.emplace_back(30, 40.5); // 直接构造,没有拷贝或移动
return 0;
}
运行结果:
Constructed with (10, 20.5)
Copy constructed
Constructed with (30, 40.5)
从上面的输出可以看出,push_back
会调用一次拷贝构造函数,而 emplace_back
直接在向量末尾构造对象,避免了额外的拷贝操作。
reserve() 方法 预留 std::vector 的容量
使用 reserve() 可以预留 std::vector 的容量,而不改变其大小。
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 预留容量为 10
vec.reserve(10);
std::cout << "Vector size: " << vec.size() << "\n"; // 输出:Vector size: 5
std::cout << "Vector capacity: " << vec.capacity() << "\n"; // 输出:Vector capacity: 10
return 0;
}
上面代码,虽然 vec 的实际大小仍然是原来的大小(5),但容量增加到了至少能容纳 10 个元素的大小。这对于避免多次动态分配内存,提高性能是有帮助的,特别是在你知道 std::vector 将来会存储更多元素的情况下。
reserve(n) 只有在需要时才会增加容量,而不会减少容量,因此如果 n 小于当前容量,容量保持不变。
比如vec初始大小为5,调用vec.reserve(2) 不会改变vec.capacity()
resize()方法 改变 std::vector 的大小
resize() 函数用于改变 std::vector 的大小,可以增加或减少元素数量。如果增加大小,新元素会被默认初始化。如果减少大小,多余的元素会被删除。
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.resize(7);
std::cout << "Vector size: " << vec.size() << "\n"; // 输出:Vector size: 7
std::cout << "Vector capacity: " << vec.capacity() << "\n"; // 输出:Vector capacity: 10
return 0;
}
为什么resize分配了7,而capacity容量确是10?
std::vector 的 capacity 是由标准库实现管理的,以优化性能和内存使用。resize 方法改变的是 size(元素数量),而不是 capacity(已分配内存)。当 resize 增加 size 时,vector 可能会重新分配内存以容纳新元素,新的 capacity 往往是以某种策略(例如倍增策略)增加的,以减少将来频繁分配内存的次数。
clear()方法 移除 std::vector 的所有元素
std::vector 的 clear 方法用于移除 vector 中的所有元素,但不改变 vector 的容量(capacity)。也就是说,clear 会将 vector 的大小(size)变为零,但 vector 仍然保留它已经分配的内存。
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.clear();
std::cout << "Vector size: " << vec.size() << "\n";
std::cout << "Vector capacity: " << vec.capacity() << "\n";
for (int i : vec) {
std::cout << i << " ";
}
return 0;
}
检查方法
vec.size()
容器中的元素数量vec.empty()
容器是否为空vec.capacity()
容器容量
删除元素
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 删除最后一个元素
vec.pop_back();
// 使用迭代器删除指定位置的元素
vec.erase(vec.begin() + 1); // 删除第二个元素
// 清空 vector
vec.clear();
std::cout << "Size after clear: " << vec.size() << std::endl;
return 0;
}
遍历元素
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用下标遍历
for (size_t i = 0; i < vec.size(); ++i) {
std::cout << vec[i] << " ";
}
std::cout << std::endl;
// 使用迭代器遍历
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// 使用范围for循环
for (const auto &elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
修改元素
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 修改元素值
vec[0] = 10;
vec.at(1) = 20;
for (const auto &elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}