array 容器
array 容器是 C++ 11 标准中新增的序列容器,简单地理解,它就是在 C++ 普通数组的基础上,添加了一些成员函数和全局函数。
和其它容器不同,array 容器的大小是固定的,无法动态的扩展或收缩,这也就意味着,在使用该容器的过程无法借由增加或移除元素而改变其大小,它只允许访问或者替换存储的元素。
array 容器以类模板的形式定义在 <array>
头文件,并位于命名空间 std 中
#include <array>
using namespace std;
在 array<T,N>
类模板中,T 用于指明容器中的存储的具体数据类型,N 用于指明容器的大小,需要注意的是,这里的 N 必须是常量,不能用变量表示。
初始化
-
创建一个名为 values 的 array 容器,其包含 10 个浮点型元素,如果程序中已经默认指定了 std 命令空间,这里可以省略 std::
std::array<double, 10> values;
-
通过如下创建 array 容器的方式,可以将所有的元素初始化为 0 或者和默认元素类型等效的值:
std::array<double, 10> values {};
-
在创建 array 容器的实例时,也可以像创建常规数组那样对元素进行初始化:
std::array<double, 10> values {0.5,1.0,1.5,,2.0};
这里只初始化了前 4 个元素,剩余的元素都会被初始化为 0.0
成员函数
成员函数 | 功能 |
---|---|
begin() | 返回指向容器中第一个元素的随机访问迭代器。 |
end() | 返回指向容器最后一个元素之后一个位置的随机访问迭代器,通常和 begin() 结合使用。 |
rbegin() | 返回指向最后一个元素的随机访问迭代器。 |
rend() | 返回指向第一个元素之前一个位置的随机访问迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
size() | 返回容器中当前元素的数量,其值始终等于初始化 array 类的第二个模板参数 N。 |
max_size() | 返回容器可容纳元素的最大数量,其值始终等于初始化 array 类的第二个模板参数 N。 |
empty() | 判断容器是否为空,和通过 size()==0 的判断条件功能相同,但其效率可能更快。 |
at(n) | 返回容器中 n 位置处元素的引用,该函数自动检查 n 是否在有效的范围内,如果不是则抛出 out_of_range 异常。 |
front() | 返回容器中第一个元素的直接引用,该函数不适用于空的 array 容器。 |
back() | 返回容器中最后一个元素的直接应用,该函数同样不适用于空的 array 容器。 |
data() | 返回一个指向容器首个元素的指针。利用该指针,可实现复制容器中所有元素等类似功能。 |
fill(val) | 将 val 这个值赋值给容器中的每个元素。 |
array1.swap(array2) | 交换 array1 和 array2 容器中的所有元素,但前提是它们具有相同的长度和类型。 |
除此之外,C++ 11 标准库还新增加了 begin() 和 end() 这 2 个函数,和 array 容器包含的 begin() 和 end() 成员函数不同的是,标准库提供的这 2 个函数的操作对象,既可以是容器,还可以是普通数组。当操作对象是容器时,它和容器包含的 begin() 和 end() 成员函数的功能完全相同;如果操作对象是普通数组,则 begin() 函数返回的是指向数组第一个元素的指针,同样 end() 返回指向数组中最后一个元素之后一个位置的指针(注意不是最后一个元素)。
在 <array>
头文件中还重载了 get()
全局函数,该重载函数的功能是访问容器中指定的元素,并返回该元素的引用。
#include <iostream>
//需要引入 array 头文件
#include <array>
using namespace std;
int main()
{
std::array<int, 4> values{};
//初始化 values 容器为 {0,1,2,3}
for (int i = 0; i < values.size(); i++) {
values.at(i) = i;
}
//使用 get() 重载函数输出指定位置元素
cout << get<3>(values) << endl;
//如果容器不为空,则输出容器中所有的元素
if (!values.empty()) {
for (auto val = values.begin(); val < values.end(); val++) {
cout << *val << " ";
}
}
}
output
3
0 1 2 3
array随机访问迭代器
begin() 和 end() 成员函数
array 容器模板类中的 begin() 和 end() 成员函数返回的都是正向迭代器,它们分别指向「首元素」和「尾元素+1」 的位置。在实际使用时,我们可以利用它们实现初始化容器或者遍历容器中元素的操作。
#include <iostream>
//需要引入 array 头文件
#include <array>
using namespace std;
int main()
{
array<int, 5>values;
int h = 1;
auto first = values.begin();
auto last = values.end();
//初始化 values 容器为{1,2,3,4,5}
while (first != last)
{
*first = h;
++first;
h++;
}
first = values.begin();
while (first != last)
{
cout << *first << " ";
++first;
}
return 0;
}
cbegin() 和 cend() 成员函数
array 模板类还提供了 cbegin() 和 cend() 成员函数,它们和 begin()/end() 唯一不同的是,前者返回的是 const 类型的正向迭代器,这就意味着,有 cbegin() 和 cend() 成员函数返回的迭代器,可以用来遍历容器内的元素,也可以访问元素,但是不能对所存储的元素进行修改。
#include <iostream>
//需要引入 array 头文件
#include <array>
using namespace std;
int main()
{
array<int, 5>values{1,2,3,4,5};
int h = 1;
auto first = values.cbegin();
auto last = values.cend();
//由于 *first 为 const 类型,不能用来修改元素
//*first = 10;
//遍历容器并输出容器中所有元素
while (first != last)
{
//可以使用 const 类型迭代器访问元素
cout << *first << " ";
++first;
}
return 0;
}
rbegin()/rend() 和 crbegin()/crend()
array 模板类中还提供了 rbegin()/rend() 和 crbegin()/crend() 成员函数,它们每对都可以分别得到指向最一个元素和第一个元素前一个位置的随机访问迭代器,又称它们为反向迭代器。
在使用反向迭代器进行 ++ 或 – 运算时,++ 指的是迭代器向左移动一位,-- 指的是迭代器向右移动一位,即这两个运算符的功能也“互换”了。
反向迭代器用于以逆序的方式处理元素。
#include <iostream>
//需要引入 array 头文件
#include <array>
using namespace std;
int main()
{
array<int, 5>values;
int h = 1;
auto first = values.rbegin();
auto last = values.rend();
//初始化 values 容器为 {5,4,3,2,1}
while (first != last)
{
*first = h;
++first;
h++;
}
//重新遍历容器,并输入各个元素
first = values.rbegin();
while (first != last)
{
cout << *first << " ";
++first;
}
return 0;
}
output
1 2 3 4 5
crbegin()/crend() 组合和 rbegin()/crend() 组合的功能唯一的区别在于,前者返回的迭代器为 const 类型,即不能用来修改容器中的元素,除此之外在使用上和后者完全相同。
array容器访问元素的几种方式
访问array容器中单个元素
-
通过
容器名[]
的方式直接访问和使用容器中的元素,这和 C++ 标准数组访问元素的方式相同。values[4] = values[3] + 2.O*values[1];
-
为了能够有效地避免越界访问的情况,可以使用 array 容器提供的
at()
成员函数。values.at (4) = values.at(3) + 2.O*values.at(1);
-
array 容器还提供了
get<n>
模板函数,它是一个辅助函数,能够获取到容器的第 n 个元素。需要注意的是,该模板函数中,参数的实参必须是一个在编译时可以确定的常量表达式,所以它不能是一个循环变量。也就是说,它只能访问模板参数指定的元素,编译器在编译时会对它进行检查。#include <iostream> #include <array> #include <string> using namespace std; int main() { array<string, 5> words{ "one","two","three","four","five" }; cout << get<3>(words) << endl; // Output words[3] //cout << get<6>(words) << std::endl; //越界,会发生编译错误 return 0; }
-
array 容器提供了
data()
成员函数,通过调用该函数可以得到指向容器首个元素的指针。通过该指针,我们可以获得容器中的各个元素。#include <iostream> #include <array> using namespace std; int main() { array<int, 5> words{1,2,3,4,5}; cout << *( words.data()+1); return 0; }
访问array容器中多个元素
array 容器提供的 size()
函数能够返回容器中元素的个数(函数返回值为 size_t 类型)
double total = 0;
for(size_t i = 0 ; i < values.size() ; ++i)
{
total += values[i];
}
通过调用 array 容器的 empty()
成员函数,即可知道容器中有没有元素(如果容器中没有元素,此函数返回 true)
if(values.empty())
std::cout << "The container has no elements.\n";
else
std::cout << "The container has "<< values.size()<<"elements.\n";
除了借助 size() 外,对于任何可以使用迭代器的容器,都可以使用基于范围的循环
double total = 0;
for(auto&& value : values)
total += value;
#include <iostream>
#include <iomanip>
#include <array>
using namespace std;
int main()
{
array<int, 5> values1;
array<int, 5> values2;
//初始化 values1 为 {0,1,2,3,4}
for (size_t i = 0; i < values1.size(); ++i)
{
values1.at(i) = i;
}
cout << "values1[0] is : " << values1[0] << endl;
cout << "values1[1] is : " << values1.at(1) << endl;
cout << "values1[2] is : " << get<2>(values1) << endl;
//初始化 values2 为{10,11,12,13,14}
int initvalue = 10;
for (auto& value : values2)
{
value = initvalue;
initvalue++;
}
cout << "Values1 is : ";
for (auto i = values1.begin(); i < values1.end(); i++) {
cout << *i << " ";
}
cout << endl << "Values2 is : ";
for (auto i = values2.begin(); i < values2.end(); i++) {
cout << *i << " ";
}
return 0;
}