概述
我们知道,C语言提供的以[]表示的数组在作为参数传入函数时会退化为指针,因此想要传入数组长度信息,通常需要额外传参。有没有什么方法解决这一问题呢?
array 是一种C++标准模板库STL中定义的一种序列容器,它提供了对数组的初步封装。
template <class T,std::size_t N>
struct array;
array 是基于数组的数据结构,只封存了栈数组(这是它与堆数组vector的显著区别),这决定了它不是动态的,但具有良好的访问速度,实际上,它与[]原生数组是等价的,只不过作为参数时不会退化。
它同时具有原生数组的所有特性:
连续存储:元素在内存中是连续存储的,这使得访问元素非常快速。
可迭代:可以被迭代,你可以使用循环来访问它的元素。
元素容器:可以存储任何类型的元素,包括基本类型、对象、指针等。
接下来,我们介绍array类型定义的成员函数。
*注意*:本文不涉及allocator空间配置器和C++23新增的range类函数。
创建销毁
STL库提供了以下方式创建一个array。
以T表示任意类型,以size_t N表示数组长度(size_t也即无符号整数)。
聚合初始化
| 隐式声明 | array完全仿照原生数组,因此初始化时隐式声明的。 这意味着你可以完全以原生数组的方式初始化它。 array<T,N>arr={};代表构建长度为N的数组,全为0。 array<T,N>arr={1,2,3};代表构建长度为N的数组,前三个元素为1,2,3。 同样的, array<T,N>arr;与T arr[N];是相同的,两者内部都是未初始化的垃圾元素。 |
析构函数 | 隐式声明 | 与原生数组完全等价的消亡机制。 |
赋值重构
在必要时我们会对array进行重构。
重载拷贝赋值= | 隐式声明 | 完全等效于结构体赋值。即以来自另一 (struct赋值=会将依次复制其中一个struct到另一struct,数组也不例外。) |
数据访问
array同时提供了类形式的函数访问和数组形式的运算符访问。
重载[]号访问 | operator[](int pos); | 模仿原生数组的数据访问形式,如arr[3]=5; |
成员函数式访问 | at(int pos); | 返回pos处元素的引用。它与[]号相同,但会检查越界。 |
访问头元素 | front(); | 返回头元素。 |
访问尾元素 | back(); | 返回尾元素。 |
直接访问底部 | data(); | 返回array维护的栈数组的头地址。 |
迭代器
迭代器是c++STL库提供的指向容器的类型,有着类似指针的作用。
在此处,array的迭代器几乎与原生数组的指针无异。
通常定义arrat<T>::iterator it=.....来获得一个指向array某处的it迭代器。
头位置 | begin(); | 返回头位置(vector第一个元素的位置,vector为空时和end相等)。 |
尾位置 | end(); | 返回尾位置。(它指向的位置是第一个不属于vector的位置而不是vector的最后一个元素。) |
常量头位置 | cbegin();
| 返回头位置,赋值给const_iterator类型。这种迭代器不可修改容器。 |
常量尾位置 | cend(); | 返回常量尾位置。 |
逆序头位置 | rbegin(); | 返回逆序头位置,赋值给reverse_iterator类型。指向最后一个元素(与end不同),对逆序迭代器的++操作会使其向头部移动,--向尾部移动(与正序相反) |
逆序尾位置 | rend(); | 返回逆序尾位置,指向vector前面的那个不属于vector的位置(与front不同) |
常量逆序头位置 | crbegin(); | 返回常量逆序头位置,赋值给const_reverse_iterator类型。 |
常量逆序尾位置 | crend(); | 返回常量逆序尾位置。 |
内存管理
保持原生数组内存可知是stl封装array的主要目的之一。
判断是否为空 | empty(); | size==0时返回true,否则返回false。 |
获取实际长度 | size(); | 返回N。 |
获取最大长度 | max_size(); | 依旧返回N。(因为栈数组可用的最大长度就是它的实际长度) |
数据控制
array类型支持通过成员函数维护数据。
填充 | fill(const T& target); | 将数组元素全部修改为target。 |
交换 | swap(array& another); | 交换两个容器的元素。 |
Tips
array<T,0>,零长数组是有意义的,
在msvc平台(visual studio等),对于array<T,0>具有一个偏特化,对他的任何读取行为都是违法的,非读取的成员函数则是一个空函数。