一句话总结:vector底层实现了一个动态数组
vector原理
基类构成:
- M_start 容器开始的位置
- M_finish 容器结束的位置
- M_end_of_storage 最后一个元素的下一个位置
1.构造函数
- 无参构造:不申请内存空间(性能优先)
- 初始化元素个数:动态申请内存空间
2.插入元素
插入到末尾:
- 先检查空间是否足够,不够则重新申请原来二倍的空间,并将旧数据拷贝到新空间中,这个拷贝的过程很消耗性能,所以在创建vector对象时最好指定初始化元素的个数,减少拷贝带来的性能损失
插入到中间:
- 将待插入位置之后的元素全部向后移动一个位置,再插入新元素
3.删除元素
删除末尾元素
- 删除元素不会释放该元素占用的内存,只是修改(记录最后一个元素位置的指针的指向)
删除其它位置元素
- 将该位置之后的元素全部向前移动一个位置
4.读取元素
- 操作符[] ,读取指定位置的元素,返回具体元素的引用
- 函数at() ,比[]多了检查越界的功能,返回元素的引用
5.修改元素
- vector不支持直接修改
- 通过[]或at()获取元素的引用后修改
6.释放空间
- swap一个空容器
- 先clear(清除元素但空间未释放),再shink_to_fit(c++11新特性,释放未使用的内存)
vector内存增长机制
1.特点:
- 内存只增加不减少
- 内存连续
2.增长方式
- 无参构造:0,1,2,4,8,16…
- 有参构造:(10),20,40 或 (50),100,200…
3.增长的具体步骤
- 申请翻倍的空间
- 将旧数据copy到新空间
- 释放旧空间
- 插入新元素
4.注意:当vector的元素为指针时,指针被释放时不会调用指针所指对象的析构函数,需要手动释放
当 vector
的元素是指针时,vector
在释放元素时不会自动调用指针所指对象的析构函数。它只会销毁存储在 vector
中的指针(即释放指针本身的存储空间),而不会管理指针所指向的动态内存。因此,如果 vector
中的元素是指针,在销毁 vector
或删除元素之前,必须手动释放指针指向的对象,以避免内存泄漏。
例如,假设有一个存储指针的 vector
:
std::vector<MyClass*> myVector;
在删除 myVector
中的元素或销毁 myVector
之前,你需要手动释放这些指针指向的内存:
for (MyClass* ptr : myVector) {
delete ptr;
}
myVector.clear();
这样才能确保指针指向的对象也被正确释放。否则,尽管 vector
自身的内存会被释放,但由指针指向的对象内存将会泄漏。
推荐学习 https://xxetb.xetslk.com/s/p5Ibb