在C++的标准模板库(STL)中,vector
是一个非常有用的动态数组容器。它允许我们存储可变大小的同类型元素序列,并且能够动态地增长和缩小。由于其灵活性和易用性,vector
在C++编程中得到了广泛的应用。
一、vector
的基本操作
1. 包含头文件
要使用vector
,首先需要包含相应的头文件:
#include <vector>
2. 创建vector
对象
创建一个空的int
类型的vector
:
std::vector<int> v;
创建一个包含10个整数的vector
,并初始化为0:
std::vector<int> v(10, 0);
3. 添加元素
使用push_back()
函数向vector
的末尾添加一个元素:
v.push_back(1);v.push_back(2);
4. 访问元素
使用下标运算符[]
来访问vector
中的元素:
int first_element = v[0]; // 访问第一个元素v[1] = 3; // 修改第二个元素的值为3
5. 删除元素
使用erase()
函数删除指定位置的元素:
v.erase(v.begin() + 1); // 删除第二个元素
6. 遍历元素
使用迭代器或范围for循环遍历vector
中的元素:
// 使用迭代器遍历for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) { std::cout << *it << " ";}std::cout << std::endl;// 使用范围for循环遍历for (const auto& element : v) { std::cout << element << " ";}std::cout << std::endl;
7. 获取vector
的大小和容量
使用size()
函数获取vector
中元素的数量,使用capacity()
函数获取vector
当前分配的内存空间能够容纳的元素数量:
std::cout << "Size: " << v.size() << std::endl;std::cout << "Capacity: " << v.capacity() << std::endl;
二、vector
的特点和优势
动态扩展:当向vector
中添加元素时,如果当前分配的内存空间不足以容纳新元素,vector
会自动重新分配更大的内存空间,并复制或移动原有元素到新的内存空间。这个过程对用户是透明的,无需手动管理内存。连续存储:vector
中的元素在内存中是连续存储的,这使得访问和操作元素非常高效。同时,连续存储也方便了元素的遍历和查找。类型安全:vector
是模板类,可以存储任意类型的元素(包括基本数据类型、自定义类型等),并且保证了类型安全。在编译时会检查元素的类型,避免了运行时类型错误的风险。易于使用:vector
提供了丰富的成员函数和操作符重载,使得对容器的操作更加直观和方便。例如,可以使用==
运算符比较两个vector
是否相等,使用+=
运算符向vector
中添加元素等。 三、示例代码
下面是一个简单的示例代码,演示了如何使用vector
进行基本的操作:
#include <iostream>#include <vector>int main() { // 创建一个空的int类型的vector std::vector<int> v; // 向vector中添加元素 v.push_back(1); v.push_back(2); v.push_back(3); // 访问和修改元素 std::cout << "First element: " << v[0] << std::endl; // 输出:First element: 1 v[1] = 4; // 修改第二个元素的值为4 // 遍历元素并输出 std::cout << "Elements in vector: "; for (const auto& element : v) { std::cout << element << " "; } std::cout << std::endl; // 输出:Elements in vector: 1 4 3 // 删除第二个元素(现在的值为4的元素) v.erase(v.begin() + 1); // 再次遍历元素并输出 std::cout << "Elements after deletion: "; for (const auto& element : v) { std::cout << element << " "; } std::cout << std::endl; // 输出:Elements after deletion: 1 3 return 0;}
四、vector
的性能考虑
虽然vector
提供了很多便利,但在某些情况下,其性能可能并不是最优的。这主要源于vector
在动态扩展时可能涉及大量的内存分配和数据复制。以下是一些使用vector
时需要考虑的性能因素:
内存分配和复制:当vector
需要增长时,它通常会分配一个更大的内存块,并将旧元素复制到新位置。这个过程可能很耗时,特别是对于大型vector
。因此,如果你知道将要存储的元素数量,最好提前使用reserve()
函数预留足够的空间。
连续内存访问:由于vector
的元素在内存中是连续存储的,因此访问它们的性能通常很好。然而,插入或删除元素(特别是在vector
的中间)可能会导致大量元素的移动,从而影响性能。在这种情况下,使用其他数据结构(如list
或deque
)可能更为合适。
缓存友好性:由于vector
的元素是连续存储的,因此它们更容易被CPU缓存,从而提高访问速度。但是,当vector
变得非常大时,它可能无法完全适应缓存,导致性能下降。
五、高级用法和注意事项
1. 使用emplace_back()
避免不必要的复制或移动:
当你想在vector
的末尾添加一个元素时,如果元素类型是一个复杂的对象,使用emplace_back()
而不是push_back()
可以避免不必要的复制或移动操作。emplace_back()
允许你在容器内直接构造元素,而无需先创建一个临时对象再将其复制或移动到容器中。
std::vector<std::string> strVec;strVec.emplace_back("Hello"); // 直接在vector中构造std::string对象
2. 使用reserve()
优化性能:
如果你知道将要添加到vector
中的元素数量,可以使用reserve()
函数提前分配足够的内存空间。这样可以避免多次重新分配内存和数据复制,从而提高性能。
std::vector<int> intVec;intVec.reserve(1000); // 预留空间以存储1000个整数for (int i = 0; i < 1000; ++i) { intVec.push_back(i);}
3. 使用shrink_to_fit()
释放未使用的内存:
在删除大量元素后,vector
可能不会立即释放未使用的内存。你可以调用shrink_to_fit()
来请求容器减小其容量以匹配当前的大小。但请注意,这只是一个请求,标准库并不保证一定会释放内存。
std::vector<int> intVec(1000);// ... 使用intVec ...intVec.clear(); // 清除所有元素intVec.shrink_to_fit(); // 请求释放未使用的内存
4. 避免在循环中多次调用size()
:
在循环中多次调用size()
函数可能会导致不必要的性能开销,特别是当循环体很大且迭代次数很多时。最好将size()
的结果存储在一个变量中,并在循环中使用该变量。
std::vector<int> intVec = {1, 2, 3, 4, 5};size_t size = intVec.size();for (size_t i = 0; i < size; ++i) { // ... 使用intVec[i] ...}
六、总结
vector
是C++ STL中非常强大且易于使用的动态数组容器。它提供了灵活的内存管理、高效的元素访问和丰富的操作函数。然而,在使用vector
时,我们也应该注意其性能特点和最佳实践,以确保代码的高效运行。通过合理使用vector
的成员函数和注意避免一些常见陷阱,我们可以充分利用这个容器的优势来编写高效且可靠的C++代码。