std::vector
是C++标准模板库(STL)中提供的一种序列容器,可以存储任意类型的对象(通过模板参数指定),对象存储在连续的内存空间中。vector
提供了动态数组的功能,但比普通数组更灵活、更安全。以下是std::vector
的一些主要使用方法:
要使用std::vector
,需要包含头文件
。
#include
std::vector vec; // 创建一个空的int类型vector
std::vector vec2(10); // 创建一个包含10个初始化为0的int元素的vector
std::vector vec3(10, 1); // 创建一个包含10个初始化为1的int元素的vector
std::vector vec4{1, 2, 3, 4, 5}; // 列表初始化
std::vector vec5(vec4.begin(), vec4.end()); // 范围初始化
std::vector vec6(vec4); // 拷贝初始化
空初始化
std::vector
这行代码创建了一个类型为 int
的空 vector
。初始时,它不包含任何元素。
默认值初始化
std::vector
创建一个包含 10 个元素的 vector
,每个元素都被初始化为 int
类型的默认值,即 0。这种初始化方式在你想要一个特定大小的 vector
,但所有元素初始值相同(并且是该类型的默认值)时非常有用。
显式值初始化
std::vector
创建一个包含 10 个元素的 vector
,每个元素都初始化为 1。这允许你创建一个具有初始非默认值的 vector
。
列表初始化
std::vector
使用花括号 {}
包含的列表直接初始化 vector
。这里,vec4
被初始化为包含五个元素 1, 2, 3, 4, 5 的 vector
。这种方式非常直观,适用于当你已知所有初始元素时。
范围初始化
std::vector
通过另一个 vector
vec4
的迭代器范围来初始化 vec5
。这种初始化方式创建了一个新的 vector
,它包含了原 vector
vec4
中所有元素的拷贝。这适用于当你需要从现有容器的一部分或全部创建一个新容器时。
拷贝初始化
std::vector
直接使用另一个 vector
vec4
来初始化 vec6
。vec6
将包含 vec4
的所有元素的拷贝。这种方式创建了一个完全相同的 vector
副本。
std::vector
vec4{1, 2, 3, 4, 5}; // 列表初始化
std::cout << vec4[2]; // 使用下标访问,不检查范围
std::cout << vec4.at(2); // 使用at方法访问,会检查范围
std::cout << vec4.front(); // 访问第一个元素
std::cout << vec4.back(); // 访问最后一个元素
使用下标访问
std::cout << vec4[2];
这行代码使用下标操作符 []
来访问 vec4
中下标为 2 的元素(即第三个元素),并将其输出。在 vec4
的情况下,这将输出 3
。下标操作符不执行范围检查,如果你尝试访问一个越界的下标,结果是未定义的,可能导致运行时错误。
使用 at
方法访问
std::cout << vec4[2];
使用 at
成员函数来访问 vec4
中下标为 2 的元素,并将其输出。at
方法与下标操作符不同,它会检查给定的下标是否在 vector
的范围内。如果下标越界(即下标大于或等于 vector
的大小),at
方法会抛出一个 std::out_of_range
异常。在 vec4
的情况下,这同样会输出 3
。
访问第一个元素
std::cout << vec4.front();
这行代码使用 front
方法获取 vec4
的第一个元素并输出它。对于 vec4
,front()
返回 1
。
访问最后一个元素
std::cout << vec4.front();
使用 back
方法来访问并输出 vec4
的最后一个元素。对于 vec4
,back()
返回 5
。
std::vector
vec4{1, 2, 3, 4, 5}; // 列表初始化
vec4.push_back(6); // 在尾部添加一个元素
vec4.pop_back(); // 移除尾部元素
vec4.insert(vec4.begin() + 2, 42); // 在指定位置插入元素
vec4.erase(vec4.begin() + 2); // 删除指定位置的元素
vec4.clear(); // 清除所有元素
在尾部添加一个元素
vec4.push_back(6);
这行代码在 vec4
的末尾添加一个元素 6
。在执行这个操作之后,vec4
的内容变为 {1, 2, 3, 4, 5, 6}
。
移除尾部元素
vec4.pop_back();
该操作移除 vec4
中的最后一个元素。如果在执行了上一个 push_back(6)
操作之后立即执行此操作,vec4
将恢复到 {1, 2, 3, 4, 5}
。
在指定位置前面插入元素
vec4.insert(vec4.begin() + 2, 42);
这行代码在 vec4
的第三个位置(即下标为 2 的位置,vector
下标从 0 开始)前面插入元素 42
。在此操作之后,如果 vec4
原先为 {1, 2, 3, 4, 5}
,那么它现在将变为 {1, 2, 42, 3, 4, 5}
。
删除指定位置的元素
vec4.erase(vec4.begin() + 2);
这个操作删除 vec4
中下标为 2 的元素,即在上一步中刚插入的 42
。在此操作之后,vec4
将恢复到插入 42
之前的状态,变为 {1, 2, 3, 4, 5}
(假设之前已经插入了 42
)。
清除所有元素
vec4.clear();
这行代码移除 vec4
中的所有元素,使其变为空 vector
。执行这个操作之后,vec4.size()
将返回 0
,表示 vec4
不包含任何元素。
std::vector
vec4{1, 2, 3, 4, 5}; // 列表初始化
std::cout << vec4.size(); // 返回vector中元素的数量
std::cout << vec4.capacity(); // 返回vector的容量
std::cout << vec4.empty(); // 检查vector是否为空
vec4.resize(10); // 改变vector中元素的数量
vec4.resize(10,5); // 改变vector中元素的数量
vec4.reserve(20); // 改变vector的容量
查询 vector
中元素的数量
std::cout << vec4.size();
size()
成员函数返回 vector
当前包含的元素数量。例如,如果 vec4
当前包含 {1, 2, 3, 4, 5}
,则 vec4.size()
将返回 5
。
查询 vector
的容量
std::cout << vec4.capacity();
capacity()
成员函数返回 vector
在需要重新分配内存之前可以容纳的元素数量。这是由于 vector
的内部实现会预留一定的空间以减少因增加元素而频繁重新分配内存的需要。
检查 vector
是否为空
std::cout << vec4.empty();
empty()
成员函数检查 vector
是否不包含任何元素。如果 vector
为空,则返回 true
;否则返回 false
。
改变 vector
中元素的数量(size)
vec4.resize(10);
resize(n)
调整 vector
的大小以包含 n
个元素。如果 n
大于当前的 size()
,则新增的元素会被默认初始化(对于整数类型,这通常意味着初始化为 0
)。 vec4.resize(10, 5);
这个 resize(n, val)
的重载版本不仅改变 vector
的大小使之包含 n
个元素,如果 n
大于当前大小,还会用 val
初始化新增的元素。在这个例子中,如果 vec4
的大小被扩展到 10 个元素,新添加的元素将被初始化为 5
。
改变 vector
的容量(capacity)
vec4.reserve(20);
reserve(n)
成员函数请求改变 vector
的容量至少为 n
。这个操作可以减少因增加元素而导致的内存重新分配的次数。如果 n
小于或等于当前的容量,这个操作不会有任何效果。reserve
不会改变 vector
的大小(即包含的元素数量)。
std::vector
vec4{1, 2, 3, 4, 5}; // 列表初始化
for (auto it = vec4.begin(); it != vec4.end(); ++it) {
std::cout << *it << " ";
}
for (auto rit = vec4.rbegin(); rit != vec4.rend(); ++rit) {
std::cout << *rit << " ";
}
正向遍历 for (auto it = vec4.begin(); it != vec4.end(); ++it) {
std::cout << *it << " ";
}
这里,it
是一个迭代器,初始化为 vec4
的开始(begin()
返回一个指向容器第一个元素的迭代器)。循环持续进行,直到迭代器 it
等于 vec4.end()
(end()
返回一个指向容器最后一个元素之后位置的迭代器,不是最后一个元素本身)。
在每次循环中,通过解引用迭代器 *it
来访问当前元素,并输出该元素值,然后迭代器通过 ++it
自增,移向下一个元素。
这种方式按顺序遍历 vector
中的所有元素。
反向遍历 for (auto rit = vec4.rbegin(); rit != vec4.rend(); ++rit) {
std::cout << *rit << " ";
}
这里使用了反向迭代器 rit
,rbegin()
返回一个指向容器最后一个元素的反向迭代器(即逻辑上的“开始”),而 rend()
返回一个指向容器第一个元素之前位置的反向迭代器(逻辑上的“结束”)。
循环以相似的方式进行,不过这次是从容器的末尾开始,通过每次自增迭代器(在反向迭代器的上下文中,自增实际上是向前移动)来逆序遍历容器中的所有元素。
这种方式按照逆序遍历 vector
中的所有元素。
std::vector
vec4{1, 2, 3, 4, 5}; // 列表初始化 std::vector vec5(vec4.begin(), vec4.end()); // 范围初始化 std::vector vec6(vec4); // 拷贝初始化
vec4.assign(5, 10); // 将vector中的内容替换为5个10
vec5.assign(array, array + sizeof(array) / sizeof(array[0]));//array数组中,0位置到结尾,替换掉vec5的内容
vec7.swap(vec4); // 交换两个vector的内容
使用 assign
方法替换 vector
的内容
vec4.assign(5, 10);
assign(n, val)
成员函数将 vec4
的内容替换为 n
个重复的 val
值。在这个例子中,vec4
的内容被替换为 5 个值为 10 的整数。如果 vec4
之前包含任何元素,这些元素会被销毁。
vec5.assign(array, array + sizeof(array) / sizeof(array[0]));
这个 assign
的重载版本接受两个迭代器作为参数,用来指定一个范围。这里使用了从数组 array
的开始到结束的范围,将 vec5
的内容替换为 array
中的元素。假设 array
是之前定义的整型数组 {1, 2, 3, 4, 5}
,则 vec5
将包含这些值。
交换两个 vector
的内容
vec7.swap(vec4);
swap
成员函数交换两个 vector
的内容。在这个例子中,vec7
和 vec4
的内容被交换。
#include
#include
using namespace std;
void TestVector1() {
vector v1;
vector v2(10, 5);
int array[] = { 1, 2, 3, 4, 5 };
vector v3(array, array + sizeof(array) / sizeof(array[0]));
vector v4(v3);
// C++11
vector v5{ 1, 2, 3, 4, 5 };
// vector的遍历
// 1. for+下标
for (size_t i = 0; i < v2.size(); ++i)
cout << v2[i] << " ";
cout << endl;
// 2. 范围for
for (auto e : v3)
cout << e << " ";
cout << endl;
// 3. 正向迭代器
vector::iterator it = v4.begin();
while (it != v4.end()) {
cout << *it << " ";
++it;
}
cout << endl;
// 4. 反向迭代器
// vector::reverse_iterator rit = v5.rbegin();
auto rit = v5.rbegin();
while (rit != v5.rend()) {
cout << *rit << " ";
++rit;
}
cout << endl;
}
/*
void resize(size_t newsize, const T& val = T())
假设当前对象的元素个数为oldsize,底层空间大小为capacity
1. oldsize < newsize < capacity
不需要扩容,直接在vector末尾填充newsize-oldsize个置为val的元素
newsize > capacity
扩容---在vecot总能填充newsize-oldsize个置为val的元素
2. newsize < oldsize 直接将有效元素个数缩减到newsize
*/
void TestVector2() {
vector v{ 1, 2, 3, 4, 5 };
v.reserve(10);
cout << v.size() << endl;
cout << v.capacity() << endl;
v.resize(8, 6);
cout << v.size() << endl;
cout << v.capacity() << endl;
v.resize(20, 7);
cout << v.size() << endl;
cout << v.capacity() << endl;
v.resize(10);
cout << v.size() << endl;
cout << v.capacity() << endl;
v.resize(3);
cout << v.size() << endl;
cout << v.capacity() << endl;
}
class A {
public:
A()
: _a()
{}
int _a;
};
int main() {
vector> vv(5);
TestVector1();
TestVector2();
return 0;
}
TestVector1
函数
展示了 std::vector
的多种初始化方法:
默认构造函数 v1
创建一个空的 vector
。
v2
通过构造函数创建一个包含 10 个元素的 vector
,每个元素初始化为 5。
v3
使用数组的首尾迭代器进行初始化,包含数组 array
的元素。
拷贝构造函数 v4
用 vector
v3
进行初始化。
列表初始化 v5
使用了 C++11 引入的初始化列表。
展示了四种遍历 vector
的方法:
使用下标遍历 v2
。
使用范围 for
循环遍历 v3
。
使用正向迭代器遍历 v4
。
使用反向迭代器遍历 v5
。
TestVector2
函数
展示了 vector
的容量管理和调整大小的方法:
初始状态下,v
包含 5 个元素。
调用 reserve(10)
,扩展 v
的容量至少可以容纳 10 个元素。
通过 resize(8, 6)
增加 v
的大小到 8,新增的元素初始化为 6。
再次通过 resize(20, 7)
增加 v
的大小到 20,新增的元素初始化为 7,这一步涉及到扩容。
resize(10)
减少 v
的大小到 10,如果 resize
的新大小小于当前大小,超出部分的元素会被删除。
最后 resize(3)
将 v
的大小减少到 3。
最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!