文章目录
C++中的std::vector是一个动态数组,它提供了在运行时改变大小的能力。std::vector是C++标准库的一部分,位于头文件中。
介绍
std::vector是一个模板类,可以存储任何类型的对象,只要该类型定义了拷贝构造函数和赋值操作符。std::vector内部使用连续的内存来存储元素,这意味着可以通过索引快速访问任何元素,就像使用普通数组一样。
优点
- 动态大小:std::vector的大小可以在运行时改变,这使得它非常适合存储大小未知的数据集。
- 连续内存:由于std::vector使用连续的内存来存储元素,因此可以通过索引快速访问任何元素。此外,这也使得std::vector能够高效地与C风格的数组和指针一起使用。
- 自动内存管理:std::vector负责其内部元素的内存分配和释放,因此不需要手动管理内存。这减少了内存泄漏和错误的可能性。
- 支持迭代器:std::vector支持迭代器,这使得它可以与STL算法一起使用,从而简化了代码并提高了效率。
- 多种成员函数:std::vector提供了许多有用的成员函数,如push_back、pop_back、resize、erase等,使得操作更加简单方便。
缺点
- 空间效率:由于std::vector使用连续的内存来存储元素,当需要增加大小时,可能需要重新分配内存并将现有元素复制到新的内存位置。这可能导致一些性能开销。
- 插入和删除的效率:在std::vector的中间位置插入或删除元素可能需要移动大量的元素,因为需要保持内存的连续性。这可能导致较高的时间复杂度(O(n))。
- 初始大小:虽然std::vector可以动态调整大小,但如果初始大小设置不当,可能会导致频繁的内存重新分配和元素复制,从而影响性能。
总的来说,std::vector是一个强大而灵活的工具,适用于许多应用场景。了解其优点和缺点有助于更好地选择合适的数据结构来解决问题。
构造函数
std::vector 是 C++ 标准库中的一个非常灵活的动态数组类模板,它提供了多种构造函数来初始化向量。以下是一些常用的 std::vector 构造函数及其描述:
默认构造函数
vector<T> v;
这个构造函数创建一个空的 vector,不包含任何元素。
带有大小和初始值的构造函数
vector<T> v(n);
vector<T> v(n, value);
这些构造函数创建一个包含 n 个元素的 vector。如果提供了 value,则所有元素都将初始化为该值;否则,对于类类型的元素,将调用其默认构造函数进行初始化。
复制构造函数
vector<T> v(const vector<T>& other);
这个构造函数创建一个与 other 向量具有相同大小和内容的副本。
移动构造函数(C++11 及以后版本)
vector<T> v(vector<T>&& other) noexcept;
这个构造函数通过移动 other 向量的资源来创建一个新的向量,other 向量在移动后将处于有效但未定义的状态。
迭代器构造函数
template <class InputIterator>
vector<T> v(InputIterator first, InputIterator last);
这个模板构造函数接受两个迭代器参数,first 和 last,它们定义了一个输入范围。新创建的 vector 将包含从 first 到 last(不包括 last)范围内的所有元素。
初始化列表构造函数(C++11 及以后版本)
vector<T> v = {a, b, c, ...};
这个构造函数使用初始化列表来创建 vector,其中 a, b, c, … 是要添加到 vector 中的初始值。
列表初始化构造函数(C++11 及以后版本)
vector<T> v{a, b, c, ...};
这与上面的初始化列表构造函数类似,但它使用花括号 {} 而不是等号 = 进行初始化。
以下是一个简单的示例,展示了如何使用 std::vector 的不同构造函数:
#include <vector>
#include <iostream>
int main() {
// 默认构造函数
std::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
// 带有大小和初始值的构造函数
std::vector<int> v2(5); // 含有5个默认初始化的int(值为0)
std::vector<int> v3(5, 3); // 含有5个值为3的int
// 复制构造函数
std::vector<int> v4(v1);
// 初始化列表构造函数
std::vector<int> v5 = {10, 20, 30};
// 列表初始化构造函数
std::vector<int> v6{40, 50, 60};
// 输出向量的内容
for (const auto& elem : v1) {
std::cout << elem << " ";
}
std::cout << "\n";
for (const auto& elem : v5) {
std::cout << elem << " ";
}
std::cout << "\n";
return 0;
}
在这个示例中,我们创建了几个 std::vector 实例,并使用了不同的构造函数来初始化它们。然后,我们遍历并打印出两个向量的内容。
析构函数
std::vector 的析构函数是自动调用的,当你不再需要一个 vector 对象时,它的析构函数就会被调用。std::vector 的析构函数负责释放向量所占用的内存,包括动态分配的元素数组以及任何可能由向量拥有的其他资源。
std::vector 的析构函数是自动调用的,你通常不需要显式调用它。它会在以下情况被调用:
- 当 vector 对象离开其作用域时。
- 当 vector 对象被销毁时,例如通过 delete 操作符删除一个指向 vector 的指针。
- 当 vector 是另一个类的成员,并且那个类的对象被销毁时。
std::vector 的析构函数会执行以下操作:
- 释放向量中存储的所有元素。如果元素是动态分配的(例如,指向其他动态对象的指针),这些元素本身不会被删除,因为它们可能由 vector 的所有者负责管理。
- 释放用于存储元素的动态分配的数组。
- 如果向量拥有任何其他资源(这通常不是 std::vector 的标准行为,但可能是通过自定义分配器或其他方式实现的),则这些资源也会被释放。
析构函数没有返回值,并且不能显式调用。它的主要目的是确保资源得到适当的清理,以防止内存泄漏和其他资源泄露问题。
下面是一个简单的例子,展示了 std::vector 析构函数的自动调用:
#include <vector>
#include <iostream>
int main() {
{
// 在这个作用域内创建一个 vector 对象
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
// 当这个作用域结束时,v 的析构函数会被自动调用
} // v 的析构函数在这里被调用,释放内存和其他资源
// v 不再存在,尝试访问它会导致未定义行为
return 0;
}
在这个例子中,当 v 离开其作用域时,它的析构函数会自动被调用,释放它所占用的内存。