目录
[🍟vector iterator 的使用](#🍟vector iterator 的使用)
[🌮vector 空间](#🌮vector 空间)
[🥪vector 增删查改](#🥪vector 增删查改)
一、vector的介绍
🍔vector官方介绍
🌟以下是vector的文档介绍:
💻官方网址:vector文档介绍
1.vector是表示可变大小数组的序列容器
2.就像数组一样,vector的元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问它们的元素,并且与数组一样高效。但与数组不同的是,它们的大小可以动态变化,容器会自动处理它们的存储
3.在内部,vector使用动态分配的数组来存储它们的元素。这个数组可能需要重新分配,以便在插入新元素时增加大小,这意味着分配一个新数组并将所有元素移动到其中。就处理时间而言,这是一个相对昂贵的任务,因此,vector不会在每次向容器中添加元素时重新分配
4.相反,vector容器可以分配一些额外的存储空间,以适应可能的增长,因此容器的实际容量可能大于包含其元素严格所需的存储空间(即其大小)。库可以实现不同的增长策略,以平衡内存使用和重新分配,但在任何情况下,重新分配应该只以对数增长的大小间隔进行,以便在向量末尾插入单个元素时可以提供平摊的常数时间复杂度(参见push_back)
5.因此,与数组相比,vector消耗更多的内存,以换取以有效的方式管理存储和动态增长的能力
6.与其他动态序列容器(deque、lists和forward_lists)相比,vector可以非常高效地访问其元素(就像数组一样),并且可以相对高效地从其末端添加或删除元素。对于涉及在末尾以外的位置插入或删除元素的操作,它们的性能比其他操作差,并且迭代器和引用的一致性不如列表和forward_lists
二、vector的使用
🍔vector的构造
💧(constructor)构造函数:
⬇️使用演示:
🍟vector iterator 的使用
💧iterator:
⬇️迭代器iterator图示:
🌮vector 空间
💧空间:
❗注意:
1️⃣****vs下capacity是按1.5倍增长的,g++是按2倍增长的. 不能固化认为,capacity的增长都是2倍.
2️⃣****reserve 只负责开辟空间,如果确定需要使用多少空间,可以缓解vector扩容耗费时间多的缺陷问题
3️⃣resize在开辟空间的同时,还会进行初始化,影响size
🥪vector 增删查改
💧vector的增删查改:
三、vector迭代器失效问题(重点)
🍔迭代器失效概念
🌟迭代器失效:
迭代器主要作用是让使用者不必关心底层的数据结构,其底层本质就是一个指针,或者对指针进行封装。因此迭代器失效就是指,迭代器底层对应指针所指向的空间被销毁 了,而使用了一块已经被释放的空间 ,最后造成程序崩溃。
🍟造成迭代器失效的原因
🔥对空间进行改变的操作都有可能造成迭代器失效
1️⃣resize 、reserve 、insert 、assign 、push_back等操作
❗程序崩溃: 在vector底层空间的改变后,it_begin和 it_end 仍使用已被释放的空间
2️⃣ 指定位置元素的删除-erase:
❗**程序崩溃:**erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是vs检查比较严格,会直接报错. 在Linux下 g++编译器就不会报错
🌟 总结:
相同的,对于string来说,如果迭代器底层指针指向的空间发生变化后我们仍然去使用,就会导致程序崩溃.
为了避免迭代器失效,在使用之前,对迭代器重新赋值即可
四、vector拷贝问题
🍔使用memcpy拷贝问题
在空间扩容时,我们可能会使用memcpy将原空间的内容拷贝到新空间,这样操作有什么问题呢?
❓问题分析:
1️⃣memcpy是内存的二进制格式拷贝 ,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
2️⃣如果拷贝的是内置类型 的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。
🌟对于内置类型:
🌟对于自定义类型:
🔥总结::如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃
五、结语
代码复现见:vector代码复现
🫡 你的点赞和关注是作者前进的动力!
🌞最后,作者主页有许多有趣的知识,欢迎大家关注作者,作者会持续更新有意思的代码 ,在有趣的玩意儿中成长!