STL 中vector
一、vector简介
1.vector是表示可以改变大小的数组的序列容器。
底层数据结构:动态开辟的数组,每次以原来空间的1.5倍进行扩容。
添加操作
vector<int> a;
a.push_back(20);//再末尾添加元素
a.insert(it,20);//it迭代器指向的位置添加一个元素20 O(n) 有可能导致容器扩容,插入一个元素,后边所有的的元素都要向后挪动一个位置
可以简单理解下图
容器中进行对象的构造和析构1,内存开辟和释放,都是通过容器的空间配置器allocator(负责内存开辟)和deallocator(负责内存释放),construct(对象构造),destory(对象析构) 。
2.删除操作
a.pop_back();//从末尾删除 时间复杂度O(1)
a.erase(it);//删除it迭代器指向的元素
删除之后,删除点之后的元素都得向前挪动
3.访问数据
1.使用for循环,由下标访问;
2.使用at()访问
3.使用迭代器访问,可以理解为面向对象的指针
4.常性迭代器,无法改变值,只可取值
5.基于范围for循环,这里使用的引用,如果是变量,每一步都需要拷贝构造
示例
class Object
{
private:
int num;
public:
Object(int x = 0) : num(x)
{
cout << "Create Object: " << this << endl;
}
~Object()
{
cout << "Destroy Object: " << this << endl;
}
Object(const Object& obj) :num(obj.num)
{
}
Object& operator=(const Object& obj)
{
if (this != &obj)
{
num = obj.num;
}
return *this;
}
int& Value() { return num; }
const int& Value()const { return num; }
};
int main()
{
vector<Object> vec = { Object(10),Object(20),Object(30) };
for (int i = 0; i < vec.size(); ++i)
{
cout << vec[i].Value() << endl;
}
for (int i = 0; i < vec.capacity(); ++i)
{
cout << vec.at(i).Value() << endl;
}
vector<Object>::iterator it = vec.begin();
for (; it != vec.end(); ++it)
{
cout << it->Value() << " ";
it->Value() += 10;
cout << it->Value() << endl;
}
vector<Object>::const_iterator it2 = vec.begin();
for (; it2 != vec.end(); ++it2)
{
cout <<it2->Value() << " ";
}
cout << endl;
for (auto& x : vec)
{
cout << x.Value() << " " << endl;
}
cout << endl;
return 0;
}
4.reserve()预留存储空间
所需参数
void reserve(size_type new_cap);
增加vector的容量到大于或等于new_cap,若new_cap大于当前capacity(),则重新分配空间;
如果小于capacity(),则不处理
int main()
{
vector<Object>vec = { Object(10),Object(20),Object(30) };
cout << vec.size() << endl;
cout << vec.capacity() << endl;
vec.reserve(10);
cout << vec.size() << endl;
cout << vec.capacity() << endl;
return 0;
}
迭代器失效问题
在使用reserve()时,new_cap大于capacity,需要重新申请空间,那么迭代器的指向原有空间会被析构,造成迭代器失效。
需要注意的是reserve()函数给vector预分配储存大小,但没有给这段内存初始化,导致vector可以利用这段存储空间,但并不能有效访问这些空间,如果访问就会出现越界现象,导致程序奔溃
5.resize()改变容器大小,并且创建对象
如果resize()的参数大于原来的capacity,那么
1.重新申请空间
2.再对申请的额外的空间初始化为0;
3.把原数据拷贝过来;
int main()
{
vector<Object>vec = { Object(10),Object(20),Object(30) };
cout << vec.size() << endl;
cout << vec.capacity() << endl;
vec.resize(10);
cout << vec.size() << endl;
cout << vec.capacity() << endl;
return 0;
}
6.assign()
void assign(size_t count,_Ty());
此函数与上面两个函数不同之处在于
1.先构造一个目标对象;
2.析构之前对象
3.拷贝构造这个对象count次
4.析构目标对象
int main()
{
vector<Object>vec = { Object(10),Object(20),Object(30) };
cout << vec.size() << endl;
cout << vec.capacity() << endl;
vec.assign(10,Object(100));
cout << vec.size() << endl;
cout << vec.capacity() << endl;
return 0;
}
7.push_back()和emplace_back()
push_back()在容器末尾插入一个元素,如果插入时空间不足遇到扩容问题,就会造成迭代器失效。
示例
在初始化后迭代器还能使用,,再push_back()后空间扩容,之前的对象会被析构掉,迭代器失效。
int main()
{
vector<Object>vec = { Object(10),Object(20),Object(30) };
cout << vec.size() << endl;
cout << vec.capacity() << endl;
vector<Object>::iterator it = vec.begin();
cout << it->Value() << endl;
vec.push_back(Object(40));
cout << it->Value() << endl;
cout << vec.size() << endl;
cout << vec.capacity() << endl;
return 0;
}
要是迭代器正常使用,可以在一开始就给容器增容。
示例
int main()
{
vector<Object>vec;
vec.reserve(10);
vec= { Object(10),Object(20),Object(30) };
vector<Object>::iterator it = vec.begin();
cout << it->Value() << endl;
vec.push_back(Object(40));
cout << it->Value() << endl;
return 0;
}
emplace_back()原位构造
int main()
{
vector<Object>vec;
vec.reserve(10);
vec= { Object(10),Object(20),Object(30) };
vector<Object>::iterator it = vec.begin();
cout << it->Value() << endl;
vec.emplace_back(Object(40));
cout << it->Value() << endl;
return 0;
}
区别:
push_back()构造时,是先构造一个无名对象,再对其拷贝构造后插入末尾,然后析构无名对象。
emplace_back()构造时,直接将值给对象的构造函数,通过定位new来实现构造。