文章目录
1.std::vector
1.1.是C++标准库中的一个类模板
也就是说,std::vector
首先是一个类,其次是一个模板类,也就是传入不同的模板参数,可以得到不同的类。
1.2.与内建数组相比更侧重于易用性
C/C++为了性能考虑对内建数组的很多行为进行了限制,比如不允许数组的复制。而vector
为了易用性牺牲了一部分性能,允许复制。其次vector可以在运行期间改变元素个数,这个对于内建数组是不支持的,内建数组的大小在编译期间就确定了。
int a[3]; // 编译期间确定内建数组大小
std::vector<int> b; // 没有初始化,那么默认b的大小是0,也就是里面没有任何元素,此时是不能访问b的!
// 数组不允许复制,vector允许
int a1[3] = a; // 错误
std::vector<int> b1 = b; // 正确,允许复制
1.3.构造与初始化
- 聚合初始化:因为在语言的发展过程中是先出现了内建数组,后来出现了
vector
,因此为了保证和内建数组一些特性相同,有聚合初始化的方式。
int a[3] = {1, 2, 3};
std::vector<int> b = {1, 2, 3};
std::vector<int> c{1, 2, 3};// 等价于std::vector<int> c = {1, 2, 3};
- 其他初始化方式
- 缺省初始化:vector是一个模板类,使用默认构造函数就是缺省初始化,此时数组中元素个数是0,此时不能访问数组中的元素,否则会导致内存错误!
- 初始化元素个数:使用
std::vector<int> b(3)
这种方式,即在()
中写入要初始化的数组元素个数。此时数组中的所有元素会被初始化成默认值,如果是int
类型那么会被初始化成0. - 同时初始化元素个数和默认值:使用
std::vector<int> b(3, 1)
,此时元素个数是3,每个元素的默认值都是1. - 注意 :注意区分简写的聚合初始化(使用
{}
构造) 与 同时初始化元素个数和默认值(使用()
构造) 的区别!
// 1.缺省,数组大小是0,此时不能访问!
std::vector<int> a;
// 2.初始化元素个数,此时元素会被初始化成默认值
std::vector<int> b(3);
// 3. 同时初始化元素个数和默认值
std::vector<int> c(3, 1); // 3个元素,都是1
// 注意和聚合初始化的简写方式区分!
std::vector<int> d{3, 1}; // 两个元素,分别是3和1
1.4.其他方法
- 获取元素个数
size
,判断是否为空empty
; - 插入删除元素
push_back
,pop_back
- vector比较:
=
<
等,就是逐个比较每个元素的大小
1.5.元素的索引与遍历
- 使用
[]
索引和使用at
方法:二者的区别是使用[]
和数组一样,可能会存在访问越界的错误,但是这个错误在编译期间是不会被发现的,只有运行期间会报错内存访问错误。而at
方法加入了内存检测机制,在运行期间报错的时候,会明确指出来你所索引的范围超过了vector
的size,这样对程序来说更加友好。
std::vector<int> a(3);
std::cout << a[20]; // 报错提示不明显
std::cout << a.at(20); // 报错明确提示是因为索引超过了vector的size
- 使用
std::begin(x)/std::end(x)
获得首位迭代器,或者使用内建的begin()/end()
方法获得首位迭代器访问元素。注意,这里得到的是迭代器,而如果是内建数组的话,得到的就是指向数组起止位置的指针。
1.6.迭代器
- 模拟指针的行为
- 包含多种类别的迭代器,每种类别的迭代器支持的操作不同。
- 比如vector对应的是随机访问类型的迭代器,支持的操作如下:
(1)解引用与下标访问:与数组类似
(2)移动
(3)两个迭代器相减求距离
(4)两个迭代器比较大小
std::vector<int> a = {1, 2, 3};
auto begin = a.begin();
auto end = a.end();
*begin; // 解引用
begin[0]; // 访问第0个元素
end - begin; // 得到vector的长度
1.7.vector相关的其他内容
- 在vector中添加元素可能使迭代器失效,如下代码假设在for循环中修改了vector,那么起止迭代器可能失效。
std::vector<int> a = {1, 2, 3};
auto begin = a.begin();
auto end = a.end();
for(; begin != end; begin++)
{
a.push_back(4);
}
类似可能是迭代器失效的函数还有:
- 多维vector
// 多维vector,定义比内建数组要复杂一些
std::vector<std::vector<int>> x;
x.push_back(vector<int>());
x[0].push_back(1);
std::cout << x[0][0];
// 优势:可以让每个vecotr的维度不相等
std::vectro<std::vector<int>> x = {{1, 2, 3}, {1, 2}};
2.std::string
疑问 :为什么std::cout << ptr
会直接输出这个指针的内容?不应该写成std::cout << *ptr
吗?这个问题在前面讲使用指针对内建数组的外部声明的时候就提到过,这里又出现了。