第17章总结
本节阅读量:章节回顾
固定大小的数组(或固定长度的数组)要求在实例化时知道数组的长度,并且该长度不能在以后更改。C样式数组和std::array都是固定大小的数组。动态数组可以在运行时调整大小。vector是一个动态数组。
std::array的长度必须是常量表达式。通常,为长度提供的值将是整型字面值、constexpr变量或非限定作用域枚举元素。
std::array是聚合。这意味着它没有构造函数,而是使用聚合初始化进行初始化。
尽可能将std::array定义为constexpr。如果您的std::array不是constexpr,请考虑改用std::vector。
使用类模板参数演绎(CTAD)让编译器从其初始值设定项推断std::array的类型和长度。
std::array实现为模板结构,其声明如下:
|
|
表示数组长度(N)的非类型模板参数的类型为std::size_t。
要获取std::array的长度,请执行以下操作:
- 我们可以使用size()成员函数询问std::array对象的长度(该函数将长度返回为无符号size_type)。
- 在C++17中,我们可以使用std::size()非成员函数(对于std:∶array,该函数仅调用size()成员函数,从而将长度返回为无符号size_type)。
- 在C++20中,我们可以使用std::ssize()非成员函数,该函数将长度返回为一个大的有符号整数类型(通常为std::ptrdiff_t)。
这三个函数都将以constexpr值的形式返回长度,除非在通过引用传递的std::array上调用。P2280在C++23中解决了此缺陷。
要索引std::array,请执行以下操作:
- 使用下标运算符(运算符[])。在这种情况下不进行边界检查,传入无效索引将导致未定义的行为。
- 使用at()成员函数,该函数通过运行时边界检查进行订阅。我们建议避免使用此函数,因为我们通常希望在索引之前进行边界检查,或者希望进行编译时边界检查。
- 使用std::get()函数模板,它将索引作为非类型模板参数,并执行编译时边界检查。
可以使用具有模板参数声明的函数模板将具有不同元素类型和长度的std::array传递给函数。或者在C++20中,使用模板<typename T,auto N>。
按值返回std::array将制作数组和所有元素的副本,但如果数组很小,并且元素的复制成本不高,则这可能没问题。在某些情况下,改用输出参数可能是更好的选择。
当使用结构体、类或数组初始化std::array,并且不为每个初始值设定项提供元素类型时,您将需要一对额外的大括号,以便编译器正确解释要初始化的内容。这是聚合初始化的工件,在这些情况下,其他标准库容器类型(使用列表构造函数)不需要双大括号。
C++中的聚合支持一个名为大括号省略的概念,该概念为何时可以省略多个大括号制定了一些规则。通常,在使用单个值初始化std::array时,或者在使用类类型或数组进行初始化时,可以省略大括号,其中类型是用每个元素显式命名的。
不能有引用数组,但可以有std::reference_wrapper数组,其行为类似于可修改的左值引用。
关于std::reference_wrapper,有几点值得注意:
- Operator=将重置std::reference_wrapper(更改正在引用的对象)。
- std::reference_wrapper<T>将隐式转换为T&。
- get()成员函数可用于获取T&。当我们想要更新被引用对象的值时,这很有用。
提供了std::ref()和std::cref()函数作为快捷方式来创建std::reference_wrapper和const std:∶reference_ wrapper包装的对象。
尽可能使用static_assert来确保使用CTAD的constexpr std::array具有正确数量的初始值设定项。
C风格的数组继承自C语言,并内置于C++的核心语言中。由于C样式数组是核心语言的一部分,因此它们有自己的特殊声明语法。在C样式数组声明中,我们使用方括号([])来告诉编译器声明的对象是C样式数组。在方括号内,我们可以选择提供数组的长度,这是类型为std::size_t的整数值,它告诉编译器数组中有多少个元素。C样式数组的长度必须是常量表达式。
C样式数组是聚合,这意味着可以使用聚合初始化来初始化它们。当使用初始值设定项列表来初始化C样式数组的所有元素时,最好省略长度,并让编译器计算数组的长度。
C型数组可以通过运算符[]进行索引。C样式数组的索引可以是有符号或无符号整数,也可以是非限定作用域枚举。这意味着C样式数组不会受到标准库容器类所具有的所有符号转换索引问题的影响!
C样式数组可以是const或constexpr。
要获取C样式数组的长度,请执行以下操作:
- 在C++17中,我们可以使用std::size()非成员函数,该函数将长度返回为无符号的std::size_t。
- 在C++20中,我们可以使用std::ssize()非成员函数,该函数将长度返回为一个大的有符号整数类型(通常为std::ptrdiff_t)。
在大多数情况下,当在表达式中使用C样式数组时,数组将隐式转换为指向元素类型的指针,并用第一个元素的地址(索引为0)初始化。通俗地说,这称为数组退化。
指针算术是一种功能,它允许我们将某些整数算术运算符(加法、减法、增量或减法)应用于指针,以产生新的内存地址。给定某个指针ptr,ptr+1返回内存中下一个对象的地址(基于所指向的类型)。
从数组(元素0)的开头进行索引时使用下标,以便数组索引与元素对齐。在从给定元素进行相对定位时使用指针算法。
C样式字符串只是C样式数组,其元素类型为char或const char。因此,C样式字符串也会退化。
数组的维数是选择元素所需的索引数。
仅包含一维的数组称为一维数组。数组的数组被称为二维数组,因为它有两个下标。具有多个维度的数组称为多维数组。展平数组是降低数组维数的过程(通常降到单个维数)。
在C++23中,std::mdspan是一个视图,为连续的元素序列提供多维数组接口。
