EdwardWong
2022/11/17阅读:38主题:姹紫
C++序列容器之`array`
array
容器
array
容器是c++11
标准新增的序列容器,是在普通数组的基础上,添加了一些成员函数和全局函数。array容器的大小是固定的,无法动态的扩展或收缩。
array
容器以类模板的形式定义在<array>
头文件中,并位于命名空间std
中:
namespace std{
template <typename T, size_t N>
class array
}
因此在使用该容器前,代码需引入<array>
头文件,并默认使用std
命名空间
# include<array>
using namespace std;
在array<T,N>
类模板中,T
用于指明容器中的存储的具体数据类型,N
用于指明容器的大小,需要注意的是,这里N
必须为常量,不能使用变量。
array
的初始化
-
创建10个 double
类型元素的array
容器
std::array<double,10> values;
这样就创建好了一个名为values
的array
容器,其包含了10
个浮点型元素,但是未显式指定元素的值,因此使用这种方式创建的容器中,各个元素的值是不确定的(array容器不会做默认初始化操作)
-
所有元素初始化为 0
或者和默认元素类型等效的值:
std::array<double,10> values{}
这样容器中所有的元素都会初始化为0
当然也可以像创建常规数组那样对元素进行初始化:
std::array<double,10> values{0.5,1.0,1.5,2.0};
这样只初始化了前4
个元素,剩余的元素会被初始化为0
.

array
容器的函数


另外,在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 << " ";
}
}
}
array
随机访问迭代器
随机访问迭代器是功能最强大的迭代器,与随机访问迭代器相关的成员函数有:


begin()/end()
和cbegin()/cend()
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;
}
迭代器对象是由array
对象的成员函数begin()
和end()
返回的,对于迭代器对象的使用,就像使用普通指针一样,可以使用前缀运算符
C++11
新增了begin()
和end()
函数,当操作对象尾array
容器时,也和迭代器相关,此时与表中的begin()
、end()
成员函数相同。
auto first=std::begin(values);
auto last=std::end(values);
对于cbegin()
和cend()
成员函数,可以用来正向的访问元素,,但是不能对所存储的元素进行修改。
rbegin()/rend()
和crbegin()/crend()
这些成员函数返回的是反向迭代器。可以以逆序的方式处理元素,在使用反向迭代器进行++
或--
运算时,++
指的是迭代器向左移动一位,--
指的是迭代器向右移动一位。
访问array
容器元素的几种方式
-
容器名[]
采用这样的方式访问容器元素时,是没有做任何边界检查的,所以即使使用越界的索引值去访问或存储元素,也不会被检测到。
-
at()
成员函数
为了避免越界访问,可以使用array
容器提供的at()
成员函数
values.at(4)=values.at(3)+2.0*values.at(1)
如果传给at()
的索引值是一个越界值时,程序会抛出std::out_of_range
异常,因此当需要访问容器中某个指定元素时,尽量使用at()
-
get 模板函数
这是一个模板函数,能够获取到容器的第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; //输出words[3]-->four
cout<<get<6>(words)<<std::endl; //越界,会发生编译错误
return 0;
}
-
data()
函数
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;
}
对于任何使用迭代器的容器,都可以使用基于范围的循环
double total=0;
for(auto && value:values){
total+=value;
}
array
与数组的区别
C++
标准库保证使用array
容器存储的所有元素一定位于连续且相邻的内存中,可以通过下列代码验证:
#include<iostream>
#include<array>
using namespace std;
int main(){
array<int,5>a{1,2,3};
cout<< &a[2]<<"" &a[0]+2<<endl; //返回的是地址,&a[0]+2中的2是2个int的类型位置
return 0;
}
使用array
容器替换普通数组可以提高开发效率和运行效率,见以下几个例子:
example1
可以使用array
容器去存储char*
或const char*
类型的字符串。
#include <iostream>
#include <array>
using namespace std;
int main()
{
array<char, 50>a{1,2,3};
strcpy(&a[0], "http://c.biancheng.net/stl");
//需要保证array容器的大小能够容纳复制进来的数据,而且如果存储的是字符串时,还要保证在存储整个字符串的同时,在其后放置一个`\0`作为字符串的结束符。 `strcpy()`在拷贝字符串的同时,会自动在最后添加`\0`
//strcpy()在拷贝字符串的同时,会自动在最后添加`\0`
printf("%s", &a[0]); // %s是以字符串输出,如果要输出数组,需要将数组的位置`&a[0]`传入
return 0;
}
在上例中,&a[0]
可以使用a,data()
代替。
example2
使用array
代替普通数组,可以使用array
封装起来的函数,例如at()
函数可以有效的防止数组越界,fill()
函数可以实现数组的快速初始化,swap()
函数可以轻松的实现两个相同数组(类型相同,大小相同)中元素的互换。
#include <iostream>
#include <array>
using namespace std;
int main()
{
array<char, 50>addr1{"http://c.biancheng.net"};
array<char, 50>addr2{ "http://c.biancheng.net/stl" };
addr1.swap(addr2);
printf("addr1 is:%s\n", addr1.data());
printf("addr2 is:%s\n", addr2.data());
return 0;
}

当两个array
容器满足大小相等并且保存元素的类型相同时,两个array
容器可以直接做赋值操作
#include <iostream>
#include <array>
using namespace std;
int main()
{
array<char, 50>addr1{ "http://c.biancheng.net" };
array<char, 50>addr2{ "http://c.biancheng.net/stl" };
addr1 = addr2;
printf("%s", addr1.data());
return 0;
}
作者介绍