C++ STL序列式容器之array
一、array概述
array 容器是 C++ 11 标准中新增的序列容器,简单地理解,它就是在 C++ 普通数组的基础上,添加了一些成员函数和全局函数。在使用上,它比普通数组更安全,且效率并没有因此变差。
1、array容器创建对象的格式
array<T, N> value; //创建array对象
注意事项:
1)、使用 array 容器类型时,需要在源文件中包含头文件 array;
2)、T 用于指明容器中存储的具体数据类型,N 用于指明容器的大小,需要注意的是,这里的 N 必须是常量,不能用变量表示
2、特性
1)、和常规数组没有太大的差别,不能增加或删除元素;
2)、模板实例的元素被内部存储在标准数组中;
3)、和标准数组相比,array 容器的额外幵销很小;
4)、array容器的两个优点:
–>如果使用 at()访问数据时,当用一个非法的索引访问数组元素时,能够被检测到,因为容器知道它有多少个元素;
–>数组容器可以作为参数传给函数,而不再需要单独去指定数组元素的个数
二、array容器的使用
1、array对象初始化的方式
1)、使用初始化列表{ }初始化
array<int, 10> value {}; //将所有的元素初始化为 0 或者和默认元素类型等效的值
array<int, 10> value {1, 2, 3, 4}; //列表中的 4 个值用于初始化前 4 个元素,其余的元素都将为 0
2)、调用数组对象的成员函数 fill()初始化
array<int, 10> value;
value.fill(3); //将所有元素都设为3
fill() 函数将所有元素都设为传入的实参值
程序示例:
#include <iostream>
#include <array>
using namespace std;
int main()
{
array<int, 5> value1 {};
cout << " 默认初始化:" << endl;
for (auto a : value1)
cout << "value = " << a << endl;
cout << endl;
array<int, 5> value2 {1, 2, 3};
cout << " 部分初始化:" << endl;
for (auto a : value2)
cout << "value = " << a << endl;
cout << endl;
array<int, 5> value3;
value3.fill(10);
cout << "fill()初始化:" << endl;
for (auto a : value3)
cout << "value = " << a << endl;
return 0;
}
结果:
3)、用函数模板 iota()以连续的递增值初始化一个数组容器,它定义在头文件 numeric 中
程序示例:
#include <iostream>
#include <array>
#include <numeric>
using namespace std;
int main()
{
array<int, 5> myarray;
iota(begin(myarray), end(myarray), 1); //从1开始递增
for (auto a : myarray)
cout << a << ' ';
return 0;
}
运行结果:1 2 3 4 5
2、获取array元素的方式
可通过以下函数获取array容器的元素:
各个成员函数的用法及说明如下:
注:
1)、成员类型reference和const_reference是对数组元素的引用类型
2)、成员类型size_type是无符号整数类型size_t的别名
1、成员函数operator[]:
1)、函数原型:
reference operator[] (size_type n);
const_reference operator[] (size_type n) const;
2)、参数:元素在数组中的位置,第一个元素的位置为0而不是1
3)、返回值:返回对数组容器中位置n处元素的引用,如果数组对象是const限定的,则该函数返回const_reference。否则,它返回一个reference
4)、异常安全:如果容器的大小大于n,则该函数从不抛出异常(无抛出保证)
5)、返回的引用可用于访问或修改元素。同时访问或修改不同的元素是安全的。
程序示例:
// array::operator[]
#include <iostream>
#include <array>
using namespace std;
int main ()
{
array<int, 10> myarray;
// 初始化:
for (int i = 0; i < 10; i++)
myarray.at(i) = i + 1;
// 打印:
cout << "myarray contains:";
for (int i = 0; i < 10; i++)
cout << ' ' << myarray[i];
cout << '\n';
return 0;
}
运行结果:myarray contains: 1 2 3 4 5 6 7 8 9 10
2、成员函数 at():
1)、函数原型:
reference at ( size_type n );
const_reference at ( size_type n ) const;
2)、参数:元素在数组中的位置,第一个元素的位置为0而不是1
3)、返回值:返回数组中位置n处元素的引用,如果数组对象是const限定的,则该函数返回const_reference。否则,它返回一个reference
4)、异常安全:at()会进行下标越界的检查,当传给 at() 的索引是一个越界值时,这时会抛出 std::out_of_rang 异常;
5)、返回的引用可用于访问或修改元素。同时访问或修改不同的元素是安全的
程序示例:
// array::at()
#include <iostream>
#include <array>
using namespace std;
int main ()
{
array<int, 10> myarray;
// 初始化:
for (int i = 0; i < 10; i++)
myarray.at(i) = i + 1;
// 打印:
cout << "myarray contains:";
for (int i = 0; i < 10; i++)
cout << ' ' << myarray.at(i);
cout << '\n';
return 0;
}
运行结果:myarray contains: 1 2 3 4 5 6 7 8 9 10
3、成员函数front()
1)、函数原型:
reference front();
const_reference front() const;
2)、参数:无参数
3)、返回值:返回对数组容器中第一个元素的引用,如果数组对象是const限定的,则该函数返回const_reference。否则,它返回一个reference。
4)、异常安全:如果容器不为空,则该函数永远不会抛出异常(无抛出保证)。
否则,它将导致未定义的行为。
5)、返回的引用可用于访问或修改元素。同时访问或修改不同的元素是安全的。
程序示例:
// array::front()
#include <iostream>
#include <array>
using namespace std;
int main()
{
array<int, 3> myarray = {2, 16, 77};
cout << "front is: " << myarray.front() << endl; // 2
cout << "back is: " << myarray.back() << endl; // 77
myarray.front() = 100;
cout << "myarray now contains:";
for ( int& x : myarray )
cout << ' ' << x;
cout << '\n';
return 0;
}
运行结果:
front is: 2
back is: 77
myarray now contains: 100 16 77
4、成员函数back()
1)、函数原型:
reference back();
const_reference back() const;
2)、参数:无参数
3)、返回值:返回对数组容器中最后一个元素的引用,如果数组对象是const限定的,则该函数返回const_reference。否则,它返回一个reference。
4)、异常安全:如果容器不为空,则该函数永远不会抛出异常(无抛出保证)。
否则,它将导致未定义的行为。
5)、返回的引用可用于访问或修改元素。同时访问或修改不同的元素是安全的。
程序示例同front()。
5、成员函数data()
1)、函数原型:
value_type* data() noexcept;
const value_type* data() const noexcept;
2)、参数:无参数
3)、返回值:返回指向数组对象中第一个元素的指针,如果数组对象是const限定的,则该函数返回的指针为 const value_type。否则,它返回一个指向value_type类型指针。
4)、异常安全:此成员函数不会抛出异常
5)、调用不会直接访问任何包含的元素,但是返回的指针可用于访问或修改元素。同时访问或修改不同的元素是安全的
程序示例:
// array::data
#include <iostream>
#include <cstring>
#include <array>
int main ()
{
const char* cstr = "Test string";
std::array<char, 12> charray;
std::memcpy(charray.data(), cstr, 12);
std::cout << charray.data() << '\n';
return 0;
}
运行结果:Test string
6、使用非成员函数 get() ,它能够获取到容器的第 n 个元素
#include <iostream>
#include <array>
using namespace std;
int main()
{
array<int, 5> myarray {1, 2, 3};
cout << get<2>(myarray) << '\n';
return 0;
}
运行结果:3
3、array迭代器
迭代器的作用是遍历array数组类中的元素
迭代器函数:
各个成员函数的用法及说明如下:
正向迭代器begin()和end()
1、成员函数begin()
1)、函数原型:
iterator begin() noexcept;
const_iterator begin() const noexcept;
2)、参数:无参数
3)、返回值:返回指向数组容器中第一个元素的迭代器,如果数组对象是const限定的,则该函数返回const_iterator。否则,它返回一个iterator。
成员类型iterator和const_iterator是随机访问迭代器类型(分别指向元素和const元素)。
4)、异常安全:不会抛出异常。返回的迭代器的复制构造函数或者赋值运算也不会抛出
5)、不会访问容器中的元素,但是返回的迭代器可用于访问或修改元素。同时访问或修改不同的元素是安全的
2、成员函数end()
1)、函数原型:
iterator end() noexcept;
const_iterator end() const noexcept;
2)、参数:无参数
3)、返回值:返回指向最后一个元素的下一个位置的随机访问迭代器,在零大小的数组中,此函数返回的结果与array :: begin相同。如果数组对象是const限定的,则该函数返回const_iterator。否则,它返回一个iterator
4)、异常安全:不会抛出异常。返回的迭代器的复制构造函数或者赋值运算也不会抛出
5)、不会访问容器中的元素,但是返回的迭代器可用于访问或修改元素。同时访问或修改不同的元素是安全的
程序示例:
// array::begin() and end() example
#include <iostream>
#include <array>
int main ()
{
std::array<int,5> myarray = { 5, 19, 77, 34, 99 };
std::cout << "myarray contains:";
for ( auto it = myarray.begin(); it != myarray.end(); ++it )
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
运行结果:myarray contains: 5 19 77 34 99
反向迭代器rbegin()和rend()
3、成员函数rbegin()
1)、函数原型:
reverse_iterator rbegin()noexcept;
const_reverse_iterator rbegin()const noexcept;
2)、参数:无参数
3)、返回值:返回指向容器中的最后一个元素的位置,如果数组对象是const限定的,则该函数返回const_iterator。否则,它返回一个iterator。
成员类型iterator和const_iterator是反向随机访问迭代器类型(分别指向元素和const元素)。
4)、异常安全:不会抛出异常。返回的迭代器的复制构造函数或者赋值运算也不会抛出
5)、不会访问容器中的元素,但是返回的迭代器可用于访问或修改元素。同时访问或修改不同的元素是安全的
4、成员函数rend()
1)、函数原型:
reverse_iterator rend()noexcept;
const_reverse_iterator rend()const noexcept;
2)、参数:无参数
3)、返回值:返回指向数组中第一个元素的前一个位置,如果数组对象是const限定的,则该函数返回const_iterator。否则,它返回一个iterator。
成员类型iterator和const_iterator是反向随机访问迭代器类型(分别指向元素和const元素)。
4)、异常安全:不会抛出异常。返回的迭代器的复制构造函数或者赋值运算也不会抛出
5)、不会访问容器中的元素,但是返回的迭代器可用于访问或修改元素。同时访问或修改不同的元素是安全的
程序示例:
// array::rbegin/rend
#include <iostream>
#include <array>
int main ()
{
std::array<int,4> myarray = {4, 26, 80, 14} ;
std::cout << "myarray contains:";
for ( auto rit=myarray.rbegin() ; rit < myarray.rend(); ++rit )
std::cout << ' ' << *rit;
std::cout << '\n';
return 0;
}
运行结果:myarray contains: 14 80 26 4
5、成员函数cbegin()
1)、函数原型:
const_iterator cbegin()const noexcept;
2)、参数:无参数
3)、返回值:返回指向const数组容器中第一个元素的位置
4)、异常安全:不会抛出异常。返回的迭代器的复制构造函数或者赋值运算也不会抛出
5)、不会访问容器中的元素,但是返回的迭代器可用于访问它们。同时访问或修改不同的元素是安全的
6、成员函数cend()
1)、函数原型:
const_iterator cend()const noexcept;
2)、参数:无参数
3)、返回值:返回指向const数组容器中最后一个元素的下一个位置,
4)、异常安全:不会抛出异常。返回的迭代器的复制构造函数或者赋值运算也不会抛出
5)、不会访问容器中的元素,但是返回的迭代器可用于访问元素。同时访问或修改不同的元素是安全的
程序示例:
// array::cend example
#include <iostream>
#include <array>
int main ()
{
std::array<int, 5> myarray = { 15, 720, 801, 1002, 3502 };
std::cout << "myarray contains:";
for ( auto it = myarray.cbegin(); it != myarray.cend(); ++it )
std::cout << ' ' << *it; // cannot modify *it
std::cout << '\n';
return 0;
}
运行结果:myarray contains: 15 720 801 1002 3502
7、成员函数rcbegin()
1)、函数原型:
const_reverse_iterator crbegin()const noexcept;
2)、参数:无参数
3)、返回值:返回指向数组容器中最后一个元素的const_reverse_iterator,类型const_reverse_iterator是指向const元素的反向随机访问迭代器类型
4)、异常安全:不会抛出异常。返回的迭代器的复制构造函数或者赋值运算也不会抛出
5)、不会访问容器中的元素,但是返回的迭代器可用于访问它们。同时访问或修改不同的元素是安全的
8、成员函数rcend()
1)、函数原型:
const_reverse_iterator crend()const noexcept;
2)、参数:无参数
3)、返回值:返回指向const数组容器中第一个元素的前一个位置,返回类型为const_reverse_iterator,类型const_reverse_iterator是指向const元素的反向随机访问迭代器类型
4)、异常安全:不会抛出异常。返回的迭代器的复制构造函数或者赋值运算也不会抛出
5)、不会访问容器中的元素,但是返回的迭代器可用于访问元素。同时访问或修改不同的元素是安全的
程序示例:
// array::crbegin/crend
#include <iostream>
#include <array>
int main ()
{
std::array<int,6> myarray = {10, 20, 30, 40, 50, 60} ;
std::cout << "myarray backwards:";
for ( auto rit = myarray.crbegin() ; rit < myarray.crend(); ++rit )
std::cout << ' ' << *rit; // cannot modify *rit
std::cout << '\n';
return 0;
}
运行结果:myarray backwards: 60 50 40 30 20 10
4、获取array容器的容量
可通过以下函数获取容器的容量信息:
1、成员函数size()
1)、函数原型:
constexpr size_type size()noexcept;
2)、参数:无参数
3)、返回值:返回数组容器中的元素数,与运算符sizeof(以字节为单位返回大小)不同,该成员函数以元素数的形式返回数组的大小
4)、异常安全:不会抛出异常
5)、不会访问容器中的元素,同时访问或修改不同的元素是安全的
程序示例:
// array::size
#include <iostream>
#include <array>
int main ()
{
std::array<int,5> myints;
std::cout << "size of myints: " << myints.size() << std::endl;
std::cout << "sizeof(myints): " << sizeof(myints) << std::endl;
return 0;
}
运行结果:
size of myints: 5
sizeof(myints): 20
2、成员函数max_size()
1)、函数原型:
constexpr size_type max_size()noexcept;
2)、参数:无参数
3)、返回值:返回数组容器可以容纳的最大元素数
4)、异常安全:不会抛出异常
5)、不会访问容器中的元素,同时访问或修改不同的元素是安全的
程序示例:
// array::max_size
#include <iostream>
#include <array>
int main ()
{
std::array<int, 10> myints;
std::cout << "size of myints: " << myints.size() << '\n';
std::cout << "max_size of myints: " << myints.max_size() << '\n';
return 0;
}
运行结果:
size of myints: 10
max_size of myints: 10
3、成员函数empty()
1)、函数原型:
constexpr bool empty()noexcept;
2)、参数:无参数
3)、返回值:返回一个布尔值
4)、异常安全:不会抛出异常
5)、不会访问容器中的元素,同时访问或修改不同的元素是安全的
程序示例:
// array::empty
#include <iostream>
#include <array>
int main ()
{
std::array<int,0> first;
std::array<int,5> second;
std::cout << "first " << (first.empty() ? "is empty" : "is not empty") << '\n';
std::cout << "second " << (second.empty() ? "is empty" : "is not empty") << '\n';
return 0;
}
运行结果:
first is empty
second is not empty
5、修改array容器的元素
1、成员函数fill()
1)、函数原型:
void fill (const value_type& val);
2)、参数:整型
3)、返回值:无
4)、异常安全:会抛出异常
5)、容器中所有元素的值被修改为传入的参数值
程序示例:
// array::fill example
#include <iostream>
#include <array>
int main ()
{
std::array<int,6> myarray;
myarray.fill(5);
std::cout << "myarray contains:";
for ( int& x : myarray) { std::cout << ' ' << x; }
std::cout << '\n';
return 0;
}
运行结果:
myarray contains: 5 5 5 5 5 5
2、成员函数swap()
1)、函数原型:
void swap (array& x) noexcept(noexcept(swap(declval<value_type&>(), declval<value_type&>())));
2)、参数:与X类型相同(包括相同大小)数组容器
3)、返回值:无
4)、异常安全:如果调用非成员方法swap在该类型的元素不会抛出异常,那么该方法也不会抛出异常。否则,容器保证在有效的状态。
5)、参数容器和X均被修改。调用可访问两个容器中的所有元素
程序示例:
// array::fill example
#include <iostream>
#include <array>
int main ()
{
std::array<int,6> myarray;
myarray.fill(5);
std::cout << "myarray contains:";
for ( int& x : myarray) { std::cout << ' ' << x; }
std::cout << '\n';
return 0;
}
运行结果:
first: 11 22 33 44 55
second: 10 20 30 40 50
6、关系运算符
//(1)
template <class T, size_T N>
bool operator== ( const array<T,N>& lhs, const array<T,N>& rhs );
//(2)
template <class T, size_T N>
bool operator!= ( const array<T,N>& lhs, const array<T,N>& rhs );
//(3)
template <class T, size_T N>
bool operator< ( const array<T,N>& lhs, const array<T,N>& rhs );
//(4)
template <class T, size_T N>
bool operator<= ( const array<T,N>& lhs, const array<T,N>& rhs );
//(5)
template <class T, size_T N>
bool operator> ( const array<T,N>& lhs, const array<T,N>& rhs );
//(6)
template <class T, size_T N>
bool operator>= ( const array<T,N>& lhs, const array<T,N>& rhs );
程序示例:
// array comparisons
#include <iostream>
#include <array>
int main ()
{
std::array<int,5> a = {10, 20, 30, 40, 50};
std::array<int,5> b = {10, 20, 30, 40, 50};
std::array<int,5> c = {50, 40, 30, 20, 10};
if (a==b) std::cout << "a and b are equal\n";
if (b!=c) std::cout << "b and c are not equal\n";
if (b<c) std::cout << "b is less than c\n";
if (c>b) std::cout << "c is greater than b\n";
if (a<=b) std::cout << "a is less than or equal to b\n";
if (a>=b) std::cout << "a is greater than or equal to b\n";
return 0;
}
运行结果:
a and b are equal
b and c are not equal
b is less than c
c is greater than b
a is less than or equal to b
a is greater than or equal to b
参考:
1、C++ STL容器参考手册
2、C语言中文网