昨晚在家,心血来潮想了解下vector,所以翻cppreference看了看,今天便小小总结下
这是我把cppreference中我常用的摘录下来做成的思维导图,更清晰一点
迭代器是什么? 简单理解:提供遍历访问的一种方式 官方理解:是一个对象,可以循环访问C++标准库容器中的元素,并提供对各个元素的访问
cbegin的c代表的是返回const,所以他不能修改数据 rbegin的r代表反向第一个
int main()
{
std::vector<int> v = { 0,1,2,3,4,5 };
for (auto it = v.begin(); it < v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
for (auto it = v.rbegin(); it < v.rend(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
for (auto it = v.cbegin(); it < v.cend(); it++)
{
std::cout << *it << " ";
// *it = 1; 错误
}
std::cout << std::endl;
for (auto it = v.crbegin(); it < v.crend(); it++)
{
std::cout << *it << " ";
// *it = 1; 错误
}
}
输出
0 1 2 3 4 5
5 4 3 2 1 0
0 1 2 3 4 5
5 4 3 2 1 0
size:现在容器中有多少个元素
resize:当新分的内存比现在内存大时,后面新扩充的内存部分,都会用默认元素来填充,所以capacity(内存)也变大;没现在内存大时,原来内存中的元素多的元素会被删除,但是capacity不变
capacity:你分配了多少的内存,即使你里面元素减少了,但是内存也不会减少
shrink_to_fit:把多余的内存给删掉,比如元素4个,内存有5,则把多余的一个内存给干掉,注意这个函数没有返回值
reserve:是内存预留空间,但是没有给新开的内存初始化,只是说明可以利用它,但是不能有效访问空间,因为现在里面什么都没,所以元素个数其实没变。如果预留空间大于当前capacity空间则会重新分配内存 reserve:并不会删除或者添加元素,也不会改变元素的数量 reserve:这个函数设计的是只能用来增加capacity,不能用来减少capacity,传入的参数小于或等于当前的capacity,reserve函数不会做任何事情,所以capacity保持不变
v[5]:这样通过索引的只能访问已存在的元素,否则就访问越界
std::vector<int> v;
std::cout << "size:" << v.size() << std::endl;
// 0
v = { 1,2,3,4,5 };
std::cout << "size:" << v.size() << std::endl;
// 5
v = { 1,2,3,4 };
std::cout << "size:" << v.size() << std::endl;
// 4 元素为4个
std::cout << "capacity:" << v.capacity() << std::endl;
// 5 内存为5个空间大小
v.shrink_to_fit();
std::cout << "capacity:" << v.capacity() << std::endl;
// 4
v.resize(10);
std::cout << "capacity:" << v.capacity() << std::endl;
// 10
std::cout << "v[5]:" << v[5] << std::endl;
// 0 因为resize新增空间时,用默认数据来填充新增加的空间
for (auto it = v.begin(); it < v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
// 1 2 3 4 0 0 0 0 0 0
v.resize(3);
for (auto it = v.begin(); it < v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
// 1 2 3
std::cout << "capacity:" << v.capacity() << std::endl;
// 10
v.shrink_to_fit();
std::cout << "capacity:" << v.capacity() << std::endl;
// 3
v.reserve(9);
for (auto it = v.begin(); it < v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
// 1 2 3
std::cout << "capacity:" << v.capacity() << std::endl;
// 9
std::cout << "v[5]:" << v[5] << std::endl;
// 6619252 随机地址,因为reserve分配的空间还没有初始化,但是resize分配的时候也就初始化了,所以上面的v[5]是0
// 但其实这样访问是错误的v[5]这是通过[]操作符索引来访问的,但是索引访问只能访问已存在的元素,而此时已存在的元素只有1 2 3
// 这就是访问越界,因为v里面只有3个元素,5超过了有效范围
v.reserve(2);
for (auto it = v.begin(); it < v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
// 1 2 3
std::cout << "capacity:" << v.capacity() << std::endl;
// 9 因为reserve(2) 2小于9,所以什么都不做
std::vector<int> v = { 0,1,2,3,4,5,6 };
v.resize(3);
std::cout << "capacity:" << v.capacity() << std::endl;
// 7
for (auto it = v.begin(); it < v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
// 0 1 2
std::cout << "v[6]:" << v[6] << std::endl;
// 6
//std::cout << v.at(3) << std::endl;
// 代码会报错,因为at里面会检查是否访问的超过了size,也就是有效元素的范围
// 而operator[]则没有这个检查
std::cout << "v.at(2):" << v.at(2) << std::endl;
// 2
std::cout << "v.front():" << v.front() << std::endl;
// 0
std::cout << "v.back():" << v.back() << std::endl;
// 2
resize(3)执行后,应该元素里面就剩下0,1,2了,为什么v[6]还能访问呢
这和resize和迭代器工作方式有关,当调用v.resize(3);后,v的大小(size)变为3,但是capacity可能仍然保持不变。这意味着,虽然你删除了一些元素,但是这些元素占用的内存并没有被释放。因此,当你访问v[6]时,你可能仍然能够看到原来的值,因为那块内存尚未被覆盖。然而,这是非常危险的,因为这是未定义的行为。
另一方面,当你使用迭代器遍历v时,迭代器只会访问v的有效元素,也就是说,只会访问v的大小(size)范围内的元素。因此,当你执行for (auto it = v.begin(); it < v.end(); it++)时,你只会看到v的前三个元素,即0,1,2,而不会看到6,因为6已经不再v的大小范围内了。
所以,[]操作符和*it都是读取内存的值,但是他们访问的范围是不同的。[]操作符可以访问到任何位置的内存,包括超出v的大小范围的内存,而*it只能访问到v的大小范围内的内存。
assign会清除容器里以前的内容,当输入的元素比原来的容量空间小时,则原来容量空间不变 emplace替代insert emplace_back替代push_back
std::vector<int> v = { 0,1,2,3,4,5,6 };
v.resize(3);
std::cout << "capacity:" << v.capacity() << std::endl;
// 7
for (auto it = v.begin(); it < v.end(); it++)
{
std::cout << *it << " ";
}
std::cout << std::endl;
// 0 1 2
std::cout << "v[6]:" << v[6] << std::endl;
// 6
//std::cout << v.at(3) << std::endl;
// 代码会报错,因为at里面会检查是否访问的超过了size,也就是有效元素的范围
// 而operator[]则没有这个检查
std::cout << "v.at(2):" << v.at(2) << std::endl;
// 2
std::cout << "v.front():" << v.front() << std::endl;
// 0
std::cout << "v.back():" << v.back() << std::endl;
// 2