首先我们得知道一件事:为了让vector能够容乃各种各样不同类型的数据,我们这里就得使用模板来处理各种各样的情况,而且这里是类模板所以我们在创建vector对象的时候就得显示实例化,然后这个模板里面有这么一句话
class Alloc = allocator
,这里大家就不用管,他已经给了缺省参数而且这句的用处是创建一个内存池用来加快内存分配的速度,接下来我们再来看看vector有哪些不同类型的构造函数:
第一种:
explicit vector (const allocator_type& alloc = allocator_type());
这种构造函数只有一个参数,这个参数跟内存池有关并且还给了这个参数一个缺省值,所以对于第一种形式我们就可以认为他是一个无参初始化,这种初始化的结果就是vector对象里面什么内容都没有,我们可以看看下面的函数来了解这个构造函数的使用:
#include
#include
using namespace std;
void test1()
{
vector<char> v1;//创建一个空顺序表用来装char类型的数据
for (auto ch : v1)
{
cout << ch << endl;
}
}
int main()
{
test1();
return 0;
}
explicit vector (size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());
这种形式的构造函数有三个不同类型的参数,作为使用者我们只用关心前两个参数的意义,第一个参数的类型为:size_type通过官网我们可以查询到vector中size_type的意思是:无符号整型。
第二个参数的类型为const value_type,在官网中也可以找到该类型的介绍:
the first template parameter( T )的意思是:第一个模板参数类型 T,那也就是说当我们显示初始化的类型为int的话,这里的第二个参数就会转变为:const int &val = int ()
,那这个参数的意思是什么呢?首先我们知道的是:每个自定义类型都对应的构造函数,或者默认构造函数,c++中引进了模板这个概念,所以为了更好引进模板这个概念,在c++当中给每个自定义类型也创建了对应的默认构造函数,其构造的默认结果为0,我们可以通过下面的代码来验证:
int main()
{
int a = int();
double b = double();
char c = char();
cout << a << endl;
cout << b << endl;
printf("%d", c);
return 0;
}
这段代码的运行结果为:
那这个时候就有小伙伴就要问了,既然都是0的话那为什么不把缺省值改成0呢?何必要去调用构造函数呢?那么这里大家得知道一件事就是vector不仅仅能容乃内置类型的数据,他还可以容乃自定义类型的数据,如果我们把缺省值改成0的话,这个0他能初始化自定义类型吗?答案是很明显不能的,而这里的const T &val = T ()
就是通过匿名对象来调用默认构造函数,然后让val指向这个匿名对象,在创建对象的时候会根据n的值在vector对象中创建n个T类型的对象,并让val来一 一初始化这几个新创建的对象,那么这就是该形式所表示的意思,我们可以通过下面的代码来进一步了解这里的使用:
class Date
{
public:
Date(int year = 2022, int month = 11, int day = 11)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
printf("year的值为:%d ", _year);
printf("month的值为:%d ", _month);
printf("day的值为:%d ", _day);
printf("\n");
}
private:
int _year;
int _month;
int _day;
};
void test2()
{
Date d1(2022, 12, 12);
vector<Date> v1(3);
vector<Date> v2(3,d1);
cout << "接下来开始打印v1的内容:" << endl;
for (auto v : v1)
{
v.print();
}
cout << "接下来开始打印v2的内容:" << endl;
for (auto v : v2)
{
v.print();
}
}
template <class InputIterator>
vector (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
这种形式就是用迭代器来初始化新创建出来的对象,这里有三个参数第一个就是迭代器开始的地方,第二个参数就是迭代器结束的地方,第三个参数不用管,那么下面就是该形式使用的方法:
void test3()
{
vector<Date> v;
v.push_back(Date(2018, 11, 11));
v.push_back(Date(2019, 11, 11));
v.push_back(Date(2020, 11, 11));
v.push_back(Date(2021, 11, 11));
v.push_back(Date(2022, 11, 11));
vector<Date>::iterator it1 = v.begin()+1;
vector<Date>v1(it1, v.end() - 1);
for (auto v : v1)
{
v.print();
}
}
vector (const vector& x);
这个就是拷贝构造,创建一个对象的时候将另外一个对象的内容初始化给新创建的对象,比如说下面的代码:
void test4()
{
vector<Date> v1;
v1.push_back(Date(2018, 11, 11));
v1.push_back(Date(2019, 11, 11));
v1.push_back(Date(2020, 11, 11));
v1.push_back(Date(2021, 11, 11));
v1.push_back(Date(2022, 11, 11));
vector<Date>v2(v1);
for (auto v : v2)
{
v.print();
}
}
这段代码的运行结果为:
那么这就是构造函数的四种不同的形式希望大家能够理解。
当我们要往一个对象中插入许多数据时,对象会不停的进行扩容,而对象里面的扩容基本上都是异地扩容,所以当对象不停进行扩容的话,他的效率必定会降低很多,所以为了避免扩容我们这里就可以使用reserve函数来一次性提高对象的容量,该函数的形式如下:
我们可以用下面的代码来看看这个函数的使用:
void test5()
{
vector<Date> v1(5);
cout <<"对象的长度为:" << v1.size() << endl;
cout <<"对象的容量为:" << v1.capacity() << endl;
v1.reserve(100);
v1.push_back(Date(2018, 11, 11));
cout << "修改容量和插入数据之后" << endl;
cout << "对象的长度为:" << v1.size() << endl;
cout << "对象的容量为:" << v1.capacity() << endl;
}
当我们知道了如何创建并初始化一个对象时,我们这里就可以往这个对象插入一些我们想要的数据,那么这里的插入数据就可以用到下面这些数据:
首先来看看这个函数的英文介绍:
在vector对象里面这个函数的作用就是往vector对象里面插入数据,我们可以通过下面的代码来了解该函数的使用:
void test6()
{
vector<Date> v1;
cout << "对象的长度为:" << v1.size() << endl;
cout << "对象的容量为:" << v1.capacity() << endl;
v1.push_back(Date(2018, 11, 11));
v1.push_back(Date(2019, 11, 11));
v1.push_back(Date(2020, 11, 11));
v1.push_back(Date(2021, 11, 11));
cout << "插入数据之后" << endl;
cout << "对象的长度为:" << v1.size() << endl;
cout << "对象的容量为:" << v1.capacity() << endl;
cout << "其内容为:" << endl;
for (auto ch : v1)
{
ch.print();
}
}
上面的函数只能在对象的尾部进行插入数据,并且每使用一次这个函数只能插入一个数据,那这里的insert函数则可以实现在对象的任意位置插入数据,并且一下子可以插入多个数据该函数的形式如下:
这里的position是插入的位置,const value_type& val 是你要插入的数据,参数n的作用就是插入n个数据,最后一种形式就是通过迭代器将数据插入,我们可以通过下面的代码测试一下三种不同的插入:
void test7()
{
vector<Date> v;
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
cout << "没修改前三个对象的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
vector<Date> v1(v);
vector<Date> v2(v);
vector<Date> v3(v);
vector<Date>::iterator it = v.begin();
vector<Date>::iterator it1 = v1.begin() + 1;
vector<Date>::iterator it2 = v2.begin() + 1;
vector<Date>::iterator it3 = v3.begin();
v1.insert(it1, Date(2018, 18, 18));
cout << "第一种插入方式之后的内容变成:" << endl;
for (auto ch : v1)
{
ch.print();
}
v2.insert(it2,3, Date(2018, 18, 18));
cout << "第二种插入方式之后的内容变成:" << endl;
for (auto ch : v2)
{
ch.print();
}
v3.insert(it3, it, v.end());
cout << "第三种插入方式之后的内容变成:" << endl;
for (auto ch : v3)
{
ch.print();
}
}
这个函数也能往对象里面添加内容,但是这个函数的主要功能是修改对象的长度,当你修改的长度小于原本的长度的时候,resize会删除多余的数据,当你给的长度大于原本长度的时候,该函数会将多出来内容填充成你给的数据或者该类型的默认构造,我们来看看该函数的介绍:
我们可以看看下面的代码来分析两种不同的情况,第一种当给的长度大于原本长度的时候:
void test8()
{
vector<Date> v;
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
cout << "对象的长度为:" << v.size() << endl;
cout << "对象的容量为:" << v.capacity() << endl;
cout << "对象的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
v.resize(7);
cout << "修改之后对象的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
这段代码的运行结果为:
我们可以看到当长度变大之后resize会自动的将多出来的内存填补上去,这里多出来了三个所以就填补了三个,而我们没有传对应的值所以这里用的就Date的默认构造来进行填补,我们再来看看第二种情况:当修改的长度小于原本的长度的时候:
void test8()
{
vector<Date> v;
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
cout << "对象的长度为:" << v.size() << endl;
cout << "对象的容量为:" << v.capacity() << endl;
cout << "对象的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
v.resize(7);
cout << "修改之后对象的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "将长度缩小之后:" << endl;
v.resize(2);
for (auto ch : v)
{
ch.print();
}
}
代码的运行结果如下:
我们看到这里的内容确实发生了修改数据变小了。
首先来看看这个函数的介绍:
这个函数的作用就是将对象原来的内容全部清空,将你给的内容填入到该对象的空间里面去,这里的内容填充有两种形式,一个是通过迭代器来进行填充比如说下面的代码:
void test9()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之前的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之前的容量为:" << endl;
cout << v.capacity() << endl;
vector<Date> v1;
v1.push_back(Date(2017, 17, 17));
v1.push_back(Date(2017, 17, 17));
v1.push_back(Date(2017, 17, 17));
v1.push_back(Date(2017, 17, 17));
v1.push_back(Date(2017, 17, 17));
v1.push_back(Date(2017, 17, 17));
v1.push_back(Date(2017, 17, 17));
vector<Date>::iterator it1 = v1.begin();
v.assign(it1,v1.end());
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之后的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之后的容量为:" << endl;
cout << v.capacity() << endl;
}
这段代码的运行结果如下:
第二种就是通过给定的n和内容来将该内容填充n次,比如说下面的代码:
void test9()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之前的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之前的容量为:" << endl;
cout << v.capacity() << endl;
vector<Date> v1;
v.assign(3, Date(2018, 8, 17));
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之后的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之后的容量为:" << endl;
cout << v.capacity() << endl;
}
上面的函数是往对象里面填充数据,既然有数据的填充那么与之对应的就有数据的删除,这里的删除就可以用到下面的函数:
这个函数就是实现尾删,这个删除就是将vector中的最后一个数据删除,我们看可以看看这个函数的介绍:
这个函数没有任何的参数,我们可以通过下面的代码来看看该函数的使用:
void test10()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之前的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之前的容量为:" << endl;
cout << v.capacity() << endl;
v.pop_back();
cout << "使用一次pop_back之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
v.pop_back();
cout << "使用二次pop_back之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
pop_back的功能是将尾部的数据删除,并且使用一次只能删除一个数据,而erase函数则可以做到在vector对象中的任意位置删除指定元素或者删除一段区间的元素,下面是该函数的介绍:
我们可以通过下面的代码来了解一下这个函数的使用,首先是定点元素的删除:
void test11()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
vector<Date>::iterator it1 = v.begin();
v.erase(it1 + 2);
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
我们将这个代码运行一下就可以看到第三个元素被删除了:
其次就是一段元素的删除:
void test11()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
vector<Date>::iterator it1 = v.begin();
v.erase(it1+1,v.end()-1);
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
这里是一段数据的删除,这里的一段所表示的意思就是将第一个元素和最后一个元素保留其他元素都删除,我们可以看看这段代码的运行结果:
这就是该函数的使用希望大家能够理解。
上面是一段数据或者一个数据的删除,那么这里的clear函数是将全部的数据删除,我们可以看看这个函数的介绍:
这个函数的使用也非常的简单毕竟他没有参数嘛,我们可以看看下面的代码来看看这个函数的作用:
void test11()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之前的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之前的容量为:" << endl;
cout << v.capacity() << endl;
v.clear();
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之后的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之后的容量为:" << endl;
cout << v.capacity() << endl;
}
这个函数的作用是查看当前对象含有的元素个数:
可以看看下面的代码:
void test12()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "该对象的长度为:" << endl;
cout << v.size() << endl;
}
void test12()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "该对象的长度为:" << endl;
cout << v.size() << endl;
cout << "该对象的容量为:" << endl;
cout << v.capacity() << endl;
}
该函数的作用是查看该对象的内容是否为空,如果为空的话这个函数
void test12()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "该对象是否为空:";
cout << v.empty();
}
因为我们这个对象含有元素,所以这里的empty的返回值就是0,我们这里可以看看这段代码的运行结果:
当我们不往对象中插入数据时,这个函数的返回值就是1,可以看看下面的代码:
void test12()
{
vector<Date> v;
v.reserve(10);
cout << "该对象是否为空:";
cout << v.empty();
}
这个函数真没啥用,他的意义就是告诉你该对象最多能够容乃多少个元素,我们可以看看该函数的介绍和使用的代码:
对应的代码为:
void test12()
{
vector<Date> v;
v.reserve(10);
cout << "该对象是否为空:";
cout << v.empty()<<endl;
cout << "该对象最多容乃多少个元素";
cout << v.max_size()<<endl;
}
代码的运行结果为:
有时候我们要对vector中某个位置的元素进行修改,那么这里我们就可以使用下面的函数来对其内容进行修改:
因为vector存储数据的方式是在一段连续的空间进行存储,所以在vector中我们将操作符[ ]进行了重载,使其[ ]可以像数组那样通过下标来获取对应的元素和修改对应的元素,我们可以看看该重载的介绍:
我们可以通过下面的代码来看看该函数的操作:
void test13()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
v[1] = Date(2018, 18, 18);
v[2] = Date(2018, 18, 18);
v[3] = Date(2018, 18, 18);
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
代码的运行结果如下:
void test13()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
v[5] = Date(2018, 18, 18);
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
这个函数的作用和operator[ ]的作用是一样的,唯一的区别就在于对于不合法的下标at会抛异常不会报错而[ ]会报错,我们来看看这个函数的介绍:
我们来看看下面的代码:
void test14()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
v.at(1) = Date(2018, 18, 18);
v.at(2) = Date(2018, 18, 18);
v.at(3) = Date(2018, 18, 18);
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
该函数的作用就是返回vector中的第一个元素,我们可以根据这个函数来修改和打印对应的数据。
该函数的作用就是返回vector中的最后一个元素,我们可以根据这个函数来修改和打印对应的数据。
我们可以通过下面的代码来看看上面两个函数的使用:
void test15()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
v.front().print();
v.back().print();
v.front() = Date(2018, 18, 18);
v.back() = Date(2023, 1, 1);
v.front().print();
v.back().print();
}
这个就是赋值重载,将一个vector对象的内容赋值给另一个vector对象,我们可以看看该函数的介绍:
该函数的使用如下:
void test16()
{
vector<Date> v;
v.reserve(10);
v.push_back(Date(2017, 17, 17));
v.push_back(Date(2019, 19, 19));
v.push_back(Date(2020, 20, 20));
v.push_back(Date(2021, 21, 21));
v.push_back(Date(2022, 22, 22));
vector<Date> v1;
v1 = v;
for (auto ch : v1)
{
ch.print();
}
}
在vector对象当中有两个swap函数,我们来看看这两个不同的swap函数对应的介绍:
第二个:
而且在我们的库中也有一个swap函数:
那这里有两个问题,为什么库中会有两个swap函数?为什么算法库中提供了swap函数,在vector中还要自己写swap函数呢?原因很简单,库中提供的swap函数的实现方法会造成三次深拷贝,这样的话会导致效率降低,所以我们vector就自己提供了一个swap函数,那为什么要写两个呢?答案也很简单因为有些使用使用着容易把swap函数的形式写错,如果是这样的话:
我们调用swap函数应该是这样:
std::vector<int> foo (3,100);
std::vector<int> bar (5,200);
foo.swap(bar);
而很多小伙伴会写成这样:
swap(foo,bar);
这样写的话调用的就是算法库中的swap所以为了防止有小伙伴写错了形式而调用了效率更低的swap我们的库就给了一个形式
这样的话就算你写错了,调用得分也是效率更高的swap。