1.STL容器共性机制
STL容器所提供的都是值(value)寓意,而非引用(reference)寓意,也就是说当我们给容器中插入元素的时候,容器内部实施了拷贝操作,将我们要插入的元素再另行拷贝一份放入容器中,而不是将数据元素直接放进容器中,也就是说我们所提供的元素必须能够被拷贝
- 除了queue和stack之外,每个容器都提供可返回迭代器的函数,运用返回的迭代器就可以访问元素
- 通常STL不会抛出异常,需要使用者传入正确参数
- 每个容器都提供了一个默认的构造函数和默认的拷贝构造函数
- 大小相关的构造方法:1 size()返回容器中元素的个数 2 empty()判断容器是否为空
#include <iostream>
#include <vector>
using namespace std;
class Teacher{
public:
Teacher(char *name,int age){
int len = strlen(name) + 1;
this->name = new char[len];//在堆分配内存
strcpy(this->name,name);
this->age = age;
}
//拷贝构造
Teacher(const Teacher &t){
int len = strlen(t.name) + 1;
this->name = new char[len];
strcpy(this->name,t.name);
this->age = agel
}
//重载=
Teacher& operator=(Teacher &t){
int len = strlen(t.name) + 1;
if (this->name != NULL)
{
delete[] this->name;
}
this->name = new char[len];
strcpy(this->name,t.name);
this->age = agel
return *this;
}
~Teacher(){
if (this->name != NULL)
{
delete[] this->name;
}
this->age = 0;
}
char *name;
int age;
}
//测试函数 深拷贝和浅拷贝
void test01(){
//会崩溃!!原因就是指向aaaa的有两个指针,却只释放一个,下图有解
//归根结底是没有写深拷贝的拷贝构造函数或重载=运算符
Teacher t1("aaaa",19);
vector<Teacher> v;
v.push_back(t1);
}
int main(){
cout<<"hello world..."<<endl;
return 0;
}
奔溃的原因是由于我们没有提供拷贝构造函数,没有重构=操作符,vector对我们的mc对象进行了简单的浅拷贝,将拷贝的对象插入到容器中,导致我们的mc对象的data指针和容器中mc对象的拷贝对象中的data指针都指向了我们在堆内存分配的内存,当函数结束,两个对象都调用了析构函数,先调用析构函数的对象成功释放了堆区内存,后调用析构函数的对象一释放,程序就挂掉了。
原因在于两个指针指向了同一块堆区内存,这样会导致不可预知的结果,函数结束其中一个调用析构函数,销毁data指向的内存空间,而另一个对象析构的时候回挂掉
问题的解决办法就是,给我们的对象提供一个拷贝构造函数,并且重构=操作符,两个指针分别指向自己的那一块内存,互不影响。
2.STL容器使用时机
- | vector | deque | list | set | multiset | map | multimap |
---|---|---|---|---|---|---|---|
典型内存结构 | 单端数组 | 双端数组 | 双向链表 | 二叉树 | 二叉树 | 二叉树 | 二叉树 |
可随机存取 | 是 | 是 | 否 | 否 | 否 | 对key而言:是 | 否 |
元素搜寻速度 | 慢 | 慢 | 非常慢 | 快 | 快 | 对Key而言:快 | 对key而言:快 |
元素安插移除 | 尾端 | 头尾两端 | 任何位置 | - | - | - | - |
- vector的使用场景:比如软件历史操作记录的记录,我们经常查看历史记录,比如上一次记录,上上次记录,但却不会去删除记录,因为记录是事实的描述。
- deque的使用场景:比如派对购票系统,对排队着的存储可以采用deque,支持头端快速移除,尾端的快速添加。如果采用vector,则头端移除时,会移动大量数据,速度慢。
vector与deque的比较
- vector.at()比deque.at()效率高,比如vector.at(0)是固定的,deque的开始位置却是不固定的。
- 如果有大量释放操作的话,vector花的时间更少,这跟二者的内部实现有关
- deque支持头部的快速插入和快速移除,这是deque的优点
- list的使用场景:比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确定位置元素的移除插入
- set的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排序
- map的使用场景:比如按ID号存储十万个用户,想要快速要通过ID查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是vector容器,最坏情况下可能要遍历整个容器才能找到该用户