std::array
是在C++ 11标准中增加的STL容器,它的设计目的是提供与原生数组类似的功能与性能。正因此,使得std::array
有很多与其他容器不同的特殊之处,比如:std::array
的元素是直接存放在实例内部,而不是在堆上分配间;std::array
的大小必须在编译期确定。std::array
的构造函数、析构函数和赋值操作符都是编译器隐式声明的……
底层原理
std::array
底层是一段连续的固定大小的内存,实现是在struct
中定义数组作为成员变量:
std::array<int, 5> arr = {
1, 2, 3, 4, 5};
- 上述代码中,对象
arr
存储在栈中,对象中包含一个在栈上定义的数组
用于存储元素。容器的大小必须在编译期确定。
- 源码中
std::array
定义如下。 _M_elems
是定义的数组用于存储元素。
template<typename _Tp, std::size_t _Nm>
struct array
{
typedef _Tp value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* iterator; // 迭代器
typedef const value_type* const_iterator;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator; // 反向迭代器
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// Support for zero-sized arrays mandatory.
typedef _GLIBCXX_STD_C::__array_traits<_Tp, _Nm> _AT_Type; // *
typename _AT_Type::_Type _M_elems; // 定义的数组用于存储元素
...
- 上述源码中,
__array_traits
的定义有两个版本,模板申明单参数(type
)和双参数(type
、size
),便实现size == 0
的array
的原理。
template<typename _Tp, std::size_t _Nm> // _Tp为元素类型、_Nm为容器大小size
struct __array_traits
{
typedef _Tp _Type[_Nm];
static constexpr _Tp&
_S_ref(const _Type& __t, std::size_t __n) noexcept
{
return const_cast<_Tp&>(__t[__n]); }
static constexpr _Tp*
_S_ptr(const _Type& __t) noexcept
{
return const_cast<_Tp*>(__t); }
};
template<typename _Tp> // _Tp为元素类型,容器大小默认为0
struct __array_traits<_Tp, 0>
{
struct _Type {
};
static constexpr _Tp&
_S_ref(const _Type&, std::size_t) noexcept
{
return *static_cast<_Tp*>(nullptr); }
static constexpr _Tp*
_S_ptr(const _Type&) noexcept
{
return nullptr; }
};
1. std::array
1. 1 常用函数
at 通过下标获取对应元素引用
back 尾元素引用
begin iterator
cbegin const iterator
cend const iterator
crbegin iterator reverse iterator
crend iterator reverse reverse
data 底层数组
empty 容器是否为空
end iterator
fill 赋值
front 头元素引用
max_size
operator[] 通过下标获取元素引用
rbegin reverse iterator
rend reverse iterator
size
swap
1. 2 构造函数
std::array
作为聚合类,可以通过为类(default
、copy
、move
)隐式定义的函数来进行构造容器对象, 或使用 initializer lists 来构造对象:
- I. default-initialization:
a: 对于类类型,使用类的默认构造;
b: 对于默认类型如int
,元素将保持未初始化状态;
c: 若array
对象为static
的,则元素0
初始化。
std::array<int, 10> static_arr; // 默认初始化,静态对象
int main() {
std::array<int, 10> arr;
for(auto& i:arr)
cout << i << " ";
cout << endl;
for(auto& i:static_arr) // 打印静态对象array中元素
cout << i << " ";
cout << endl;
return 0;
}
0 0 0 0 4197872 0 4197168 0 226809856 32765
0 0 0 0 0 0 0 0 0 0
- 可以看出在栈中的局部变量
arr
中元素为int 随机值。 - 静态变量
static_arr
内部元素进行了0初始化。
- II. copy/move initialization: 将类型、大小相同的
array
对象的元素 复制/移动 到构造的array
中。
int main() {
std::array<int,3> arr = {
1,2,3}; // initialized as: {1,2,3}
std::array<int,3> arr_copy = arr; // copy: {1,2,3}
return 0;
}
- III. initializer list: 若
list
中的元素个数小于array.size
, 那么对于剩余元素将进行初始化(类类型为 默认初始化、 普通类型为0初始化)。
int main() {
// initialized as: {1,2,3,0,0}
std::array<int,5> arr = {
1,2,3};
return 0;
}
2. size、max_size、empty
size()
,返回容器中元素个数。max_size()
,返回容器可以容乃的最大元素个数,返回值与size()
一样,总是等于第二个模板参数_Nm
。empty()
,返回容器是否为空,即容器size是否为0。
constexpr size_type size() noexcept; // size 函数原型
constexpr size_type max_size() noexcept; // max_size
constexpr bool empty() noexcept; // empty
测试代码:
int main () {
std::array<int,5> arr_int;
std::cout << "size of arr_int: " << arr_int.size() << std::endl;
std::cout << "max_size of arr_int: " << arr_int.max_size() << '\n';
std::cout << "sizeof(arr_int): " << sizeof(arr_int) << std::endl;
std::cout << "arr_int " << (arr_int.empty() ? "is empty" : "is not empty") << '\n';
cout << endl;
std::array<int,0> arr_empty;
std::cout << "arr_empty " << (arr_empty.empty() ? "is empty" : "is not empty") << '\n';
std::cout << "sizeof(arr_empty): " << sizeof(arr_empty) << std::endl;
return 0;
}
size of arr_int: 5
max_size of arr_int: 5
sizeof(arr_int): 20
arr_int is not empty
aarr_empty is empty
sizeof(arr_empty): 1
- 可以看出,
arr_empty
使用array模板类创建的是一个空类,所有其实例化对象的sizeof
为1。 - c++中,空类和空结构体的大小是1。
3. fill、data、swap
fill()
,将容器中所有元素值设置为val
。data()
,返回指向容器中第一个元素的指针,后续可以通过指针偏移访问其他元素。swap()
,当前容器与,另一个相同类型、相同大小的array
交换容器中所有元素,如果类型或大小
不同,则无法通过编译。
void fill(const value_type& val); // fill 函数原型
value_type* data() noexcept; // data
const value_type* data() const noexcept;
// swap
void swap (array& x) noexcept(noexcept(swap(declval<value_type&>(),declval<value_type&>())));
测试代码:
int main () {
std::array<int,3> arr_first;
arr_first.fill(9); // fill(), arr_first:9 9 9
std::array<int,3> arr_second = {
10,100,1000};
arr_first.swap(arr_second); // 交换俩arr对象中元素
cout << "arr_first element: "; // data()函数获取头元素指针
int* p = arr_first.data(); // 通过指针偏移打印 arr_first 元素
for(int i=0; i<arr_first.size(); ++i)
cout << *(p+i) << " ";
return 0;
}
arr_first element: 10 100 1000