C++里的vector详细讲解

Weirdo丨 2024-10-13 09:05:03 阅读 89

在C++的标准模板库(STL)中,<code>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的中间)可能会导致大量元素的移动,从而影响性能。在这种情况下,使用其他数据结构(如listdeque)可能更为合适。

缓存友好性:由于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++代码。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。