C++基础之容器——array详解

本文详细介绍了C++中的std::array容器,包括其模板定义、成员类型和函数,如begin、end、rbegin、rend、size、front、back、data等。std::array是一个固定大小的序列容器,提供了类似于数组的功能,支持迭代器和常量迭代器,且元素存储在连续的内存空间中。此外,文章还提到了std::array与C++的数组和其它容器的区别,如其大小不可变,以及作为tuple的替代品的特性。

头文件
:头文件中定义了固定大小的数组容器array 类和两个函数begin和end。

模板类定义

原型定义

template < class T, size_t N > class array;

类介绍

数组array是一个大小固定的序列容器:容器中保存这特定数量的元素,元素按照严格的线性序列保存。
在容器内部,除了容器的元素不会保存任何其他的数据(甚至大小也不保存,大小是模板类的参数,在编译时确定)。就存储大小而言它与使用括号语法([])声明的数组一样高效。这个类只是在数组的基础上添加了成员函数和全局函数,这样数组就可以当作标准容器来使用。
与其他标准容器不同,array的大小是固定的,而且不会通过一个内存分配器来管理元素内存的分配:它是一个封装了固定数量元素的数组的聚合类型。因此,它不能动态的添加或删除元素(类似的大小可扩展的容器参见vector)。
大小为0的数组是有效的,但是不能对元素进行访问( 成员函数front、back、data)。
与标准库中的其他容器不同,交换两个array的内容,不管是全部交换还是只交换一个范围内的元素(通常效率非常地的操作),时间复杂度都是线性的。同时还使迭代器保留对原始数组的引用。
array的另一个独有的特征是,可以把array当作一个tuple对象来看待:<array>头文件中重载了get函数使array像tuple一样访问元素,还有指定的tuple_size和tuple的元素类型。

容器属性

顺序存储
容器中的元素以严格的线性序列存储。每个元素都可以通过它在序列中的位置来访问。
连续存储
容器的元素保存在一段连续的内存空间中,因此可以以常数时间复杂度来访问任意的元素(O(1))。可以通过使用指向一个元素的指针加上偏移来访问另一个元素。
大小固定
容器使用隐藏构造函数和析构函数来静态的申请和释放内存空间。容器的大小是编译时常量。没有内存或时间开销。

模板参数

T
元素的类型,别名为成员类型array::alue_type。
N
array的大小,元素的数量。

在成员函数中的参数假定与模板参数的名称相同。

成员类型

以下的别名是array的成员类型,他们广泛用于成员函数的参数和返回类型。
在这里插入图片描述

成员函数

std::array::begin

函数原型

     iterator begin() noexcept;
const_iterator begin() const noexcept;

功能
返回一个指向array容器第一个元素的迭代器。注意:与array::front函数(返回第一个元素的引用)不同,begin返回的是指向第一个元素的可以随机访问的迭代器。
在大小为0的数组中,返回值与array::end相同,但是返回的迭代器不应该解引用来访问元素。
参数

返回值
一个指向序列开始的迭代器。如果array是const的,则返回一个const_iterator,否则返回一个iterator。
成员类型iterator和const_iterator都是可以随机访问的(分别指向普通元素和静态的元素)。
Example

// array::begin example
#include <iostream>
#include <array>

int main ()
{
  std::array<int,5> myarray = { 2, 16, 77, 34, 50 };

  std::cout << "myarray contains:";
  for ( auto it = myarray.begin(); it != myarray.end(); ++it )
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

myarray contains: 2 16 77 34 50

复杂度
常数
迭代器有效性
不会修改迭代器的有效性。
数据竞争
该函数不会访问array的元素,但是返回的迭代器可以访问和修改元素。同时访问或修改元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。拷贝构造或在对返回的迭代器赋值都不会抛出异常。

std::array::end

函数原型

         iterator end() noexcept;
const_iterator end() const noexcept;

功能
返回一个指向array容器the past-the-end element的迭代器。
the past-the-end element是一个理论上的元素,在array最后一个元素的下一个位置。它不指向任何的元素,因此不能解引用来访问元素。
由于标准库函数访问元素范围不包括终止迭代器指向的元素,因此该函数通常用来与array::begin一起使用来指定容器的元素范围。
在大小为0的数组中,返回值与array::begin相同,但是返回的迭代器不应该解引用来访问元素。
参数

返回值
一个指向序列最后一个元素的下一个位置的迭代器。如果array是const的,则返回一个const_iterator,否则返回一个iterator。
成员类型iterator和const_iterator都是可以随机访问的(分别指向普通元素和静态的元素)。
Example

// array::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;
}

Output:

myarray contains: 5 19 77 34 99

复杂度
常数
迭代器有效性
不会修改迭代器的有效性。
数据竞争
该函数不会访问array的元素,但是返回的迭代器可以访问和修改元素。同时访问或修改元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。拷贝构造或在对返回的迭代器赋值都不会抛出异常。

std::array::rbegin和std::array::rend

函数原型

 reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;

功能
rbegin: 返回一个反向的迭代器,指向容器最后一个元素。rbegin指向的元素正好是end函数指向元素的前一个。与另一个成员函数array::back不同,back返回的是指向最后一个元素的引用,而rbegin返回的是同一个元素的迭代器,并且迭代器可以任意访问成员。
rend: 返回一个指向容器第一个元素的前面一个元素的迭代器,该元素只是理论上的元素(该元素被定为为数组的反向结束位置)。rbegin和rend之间包含了容器的所有元素。
参数

返回值
rbegin: 一个反向迭代器,该迭代器指向反向第一个元素也就是容器最后一个元素。
rend: 一个指向反向结束位置的反向迭代器。

如果array是const的,则返回的迭代器是const_iterator。否则返回一个正常的迭代器。
成员类型reverse_iterator 和 const_reverse_iterator都是反向可以随机访问的迭代器(分别指向普通元素和const元素)。
Example

// 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;
}

Output:

myarray contains: 14 80 26 4

注意: 反向迭代器是反向增长的。

复杂度
常数
迭代器有效性
不会修改迭代器的有效性。
数据竞争
该函数不会访问array的元素,但是返回的迭代器可以访问和修改元素。同时访问或修改元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。拷贝构造或在对返回的迭代器赋值都不会抛出异常。

std::array::cbegin和std::array::cend

函数原型

 const_iterator cbegin() const noexcept;
 const_iterator cend() const noexcept;

功能
cbegin: 返回指向容器第一个元素的const_iterator。const_iterator指向指向的内容是const的。迭代器可以向前和向后移动(除非它本身也是const的)。与array::begin返回的值是相同的,但是不能修改该函数返回的迭代器指向的内容,即使array本身并不是const的。
cend: 返回一个指向容器最后一个元素的下一个位置的const_iterator。与array::end返回的值是相同的,但是不能修改该函数返回的迭代器指向的内容,即使array本身并不是const的。
参数

返回值
cbegin: 返回指向容器第一个元素的const_iterator。
cend: 一个指向容器最后一个元素的下一个位置的const_iterator。

成员类型const_iterator是可以随机访问的迭代器类型,指向一个const元素。
Example

// array::cbegin example
#include <iostream>
#include <array>

int main ()
{
  std::array<int,5> myarray = { 2, 16, 77, 34, 50 };

  std::cout << "myarray contains:";

  for ( auto it = myarray.cbegin(); it != myarray.cend(); ++it )
    std::cout << ' ' << *it;   // cannot modify *it

  std::cout << '\n';

  return 0;
}

Output:

myarray contains: 2 16 77 34 50

复杂度
常数
迭代器有效性
不会修改迭代器的有效性。
数据竞争
该函数不会访问array的元素,但是返回的迭代器可以访问和修改元素。同时访问或修改元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。拷贝构造或在对返回的迭代器赋值都不会抛出异常。

std::array::crbegin和std::array::crend

函数原型

const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;

功能
功能就不再重复描述了,返回的是const 的反向迭代器。与rbegin与rend的区别就是返回的迭代器不能用来修改元素。
参数

返回值
反向的const 迭代器。
Example

// 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;
}

Output:

myarray backwards: 60 50 40 30 20 10

复杂度
常数
迭代器有效性
不会修改迭代器的有效性。
数据竞争
该函数不会访问array的元素,但是返回的迭代器可以访问和修改元素。同时访问或修改元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。拷贝构造或在对返回的迭代器赋值都不会抛出异常。

std::array::size

函数原型

constexpr size_type size() noexcept;

功能
返回容器中元素的数量。array的size总是与array类模板的参数N相等。与C++的sizeof不同,sizeof返回的是字节数,该函数返回元素数量。
参数

返回值
容器array中元素的数量,这是一个编译时常量。size_type是unsigned integer类型size_t的别名。
Example

// 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;
}

Possible output:

size of myints: 5
sizeof(myints): 20

复杂度
常数
迭代器有效性
不会变化。
数据竞争
该函数不会访问array的元素:同时访问或修改元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。

std::array::max_size

函数原型

constexpr size_type max_size() noexcept;

功能
返回容器可以保存元素的最大数量。max_size与size一样,永远与array类模板的第二个参数N相等。
参数

返回值
容器array可以保存元素的最大数量,这是一个常量。size_type是unsigned integer类型size_t的别名。
Example

// 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;
}

Possible output:

size of myints: 10
max_size of myints: 10

size和max_size总是匹配相等的。
复杂度
常数
迭代器有效性
不会变化。
数据竞争
该函数不会访问array的元素:同时访问或修改元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。

std::array::empty

函数原型

constexpr bool empty() noexcept;

功能
返回一个布尔值,来表示容器是不是空的,也就是size是不是0。该函数不会修改容器的内容。清空容器可以使用array::fill方法。
参数

返回值
如果size为0则返回True,否则返回false。返回在是常数。
Example

// 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;
}

Output:

first is empty
second is not empty

复杂度
常数
迭代器有效性
不会变化。
数据竞争
该函数不会访问array的元素:同时访问或修改元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。

std::array::operator[]

函数原型

      reference operator[] (size_type n);
const_reference operator[] (size_type n) const;

功能
返回array容器在位置n处元素的引用。功能与array::at函数的功能类似,不同的是at函数会检查n是否在有效范围内,超出范围会抛出异常。
参数
n: array中元素的位置。第一个元素从0开始标记。
返回值
指定位置的元素。如果array是const的则返回一个const的引用,否则返回一个普通的引用。成员类型reference和const_reference是指向array元素的引用类型。
Example

// array::operator[]
#include <iostream>
#include <array>

int main ()
{
  std::array<int,10> myarray;
  unsigned int i;

  // assign some values:
  for (i=0; i<10; i++) myarray[i]=i;

  // print content
  std::cout << "myarray contains:";
  for (i=0; i<10; i++)
    std::cout << ' ' << myarray[i];
  std::cout << '\n';

  return 0;
}

Output:

myarray contains: 0 1 2 3 4 5 6 7 8 9

复杂度
常数
迭代器有效性
不会变化。
数据竞争
返回的引用可以访问或着修改元素值:同时修改不同的元素是安全的。
异常&安全
如果n小于size,该函数不会抛出异常;否则会导致不确定的行为。

std::array::at

函数原型

      reference at ( size_type n );
const_reference at ( size_type n ) const;

功能
返回array容器在位置n处元素的引用。该函数会检查n是否在有效范围内,如果超出范围则抛出out_of_range的异常。相反,operator[]操作符不会检查n的有效性。
参数
n: array中元素的位置。如果大于等于size的话会抛出out_of_range的异常。注意第一个元素从0开始。
返回值
array中指定位置的元素。如果array是const的则返回一个const的引用,否则返回一个普通的引用。成员类型reference和const_reference是指向array元素的引用类型。
Example

// array::at
#include <iostream>
#include <array>

int main ()
{
  std::array<int,10> myarray;

  // assign some values:
  for (int i=0; i<10; i++) myarray.at(i) = i+1;

  // print content:
  std::cout << "myarray contains:";
  for (int i=0; i<10; i++)
    std::cout << ' ' << myarray.at(i);
  std::cout << '\n';

  return 0;
}

Output:

myarray contains: 1 2 3 4 5 6 7 8 9 10

复杂度
常数
迭代器有效性
不会变化。
数据竞争
返回的引用可以访问或着修改元素值:同时修改不同的元素是安全的。
异常&安全
强保证: 如果出现异常,不会修改容器元素。如果n超出有效范围则抛出out_of_range的异常。

std::array::front

函数原型

      reference front();
const_reference front() const;

功能
返回容器第一个元素的引用。begin返回的是一个迭代器,而此函数返回一个直接引用。在空容器上调用该函数会导致不确定的行为。
参数

返回值
第一个元素的引用。如果array是const的则返回一个const的引用,否则返回一个普通的引用。成员类型reference和const_reference是指向array元素的引用类型。
Example

// array::front
#include <iostream>
#include <array>

int main ()
{
  std::array<int,3> myarray = {2, 16, 77};

  std::cout << "front is: " << myarray.front() << std::endl;   // 2
  std::cout << "back is: " << myarray.back() << std::endl;     // 77

  myarray.front() = 100;

  std::cout << "myarray now contains:";
  for ( int& x : myarray ) std::cout << ' ' << x;

  std::cout << '\n';

  return 0;
}

Output:

front is: 2
back is: 77
myarray now contains: 100 16 77

复杂度
常数
迭代器有效性
不会变化。
数据竞争
该函数的返回值可以访问或者修改元素值。同时修改其他元素是安全的。
异常&安全
如果容器不空,不会抛出异常。否则会导致不确定的行为。

std::array::back

函数原型

      reference back();
const_reference back() const;

功能
返回容器最后一个元素的引用。end返回的是一个指向最后一个元素下一个位置的迭代器,而此函数返回一个直接引用。在空容器上调用该函数会导致不确定的行为。
参数

返回值
最后一个元素的引用。如果array是const的则返回一个const的引用,否则返回一个普通的引用。成员类型reference和const_reference是指向array元素的引用类型。
Example

// array::back
#include <iostream>
#include <array>

int main ()
{
  std::array<int,3> myarray = {5, 19, 77};

  std::cout << "front is: " << myarray.front() << std::endl;   // 5
  std::cout << "back is: " << myarray.back() << std::endl;     // 77

  myarray.back() = 50;

  std::cout << "myarray now contains:";
  for ( int& x : myarray ) std::cout << ' ' << x;
  std::cout << '\n';

  return 0;
}

Output:

front is: 5
back is: 77
myarray now contains: 5 19 50

复杂度
常数
迭代器有效性
不会变化。
数据竞争
该函数的返回值可以访问或者修改元素值。同时修改其他元素是安全的。
异常&安全
如果容器不空,不会抛出异常。否则会导致不确定的行为。

std::array::data

函数原型

      value_type* data() noexcept;
const value_type* data() const noexcept;

功能
返回指向第一个元素的指针。由于array保存在一个连续的区域内,所以可以使用该指针加上偏移来访问任意的元素。
参数

返回值
array元素的指针。如果array是const的,则返回指向 const value_type的指针,否则返回一个普通指针。value_type是容器中元素的数据类型。
Example

// 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;
}

Output:

Test string

复杂度
常数
迭代器有效性
不会变化。
数据竞争
该函数不会直接访问array的元素,但是返回的指针可以用来访问和修改元素。同时访问或修改不同的元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。

std::array::fill

函数原型

void fill (const value_type& val);

功能
将array中所有元素的值都设置成val。
参数
val: 要填充的值
返回值

Example

// 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;
}

Output:

myarray contains: 5 5 5 5 5 5

复杂度
线性的:与array的size相关
迭代器有效性
不会变化。
数据竞争
所有的数据都会变化
异常&安全
基本保证: 如果抛出异常,容器仍处于有效状态。如果赋值出现异常会抛出对应的异常信息。

std::array::swap

函数原型

void swap (array& x) noexcept(noexcept(swap(declval<value_type&>(),declval<value_type&>())));

功能
与另一个array的内容交换,两个array的数据类型和size必须相同。执行该函数后,该容器的内容与x的内容互换。与其他容器的swap不同,array的swap函数执行时间与size成线性关系。
参数
x: 与该容器类型和size相同的另一个容器。
返回值

如果其中一个元素交换出现异常,则会抛出一个异常信息。
Example

// swap arrays
#include <iostream>
#include <array>

int main ()
{
  std::array<int,5> first = {10, 20, 30, 40, 50};
  std::array<int,5> second = {11, 22, 33, 44, 55};

  first.swap (second);

  std::cout << "first:";
  for (int& x : first) std::cout << ' ' << x;
  std::cout << '\n';

  std::cout << "second:";
  for (int& x : second) std::cout << ' ' << x;
  std::cout << '\n';

  return 0;
}

Output:

first: 11 22 33 44 55
second: 10 20 30 40 50

复杂度
与size成线性关系。
迭代器有效性
迭代器、指针和引用的有效性不会变化。迭代器和指针仍然指向对应容器的位置,值变为swap后的值,但引用的值不会变,指向原来的值。
数据竞争
该容器与x容器的值都被访问和修改了。
异常&安全
如果交换没有发生异常,该函数不会抛出异常。否则基本保证容器仍处于有效状态。

非成员函数重载

std::get (array)

函数原型

template <size_t I, class T, size_t N> T& get (array<T,N>& arr) noexcept;
template <size_t I, class T, size_t N> T&& get (array<T,N>&& arr) noexcept;
template <size_t I, class T, size_t N> const T& get (const array<T,N>& arr) noexcept;

功能
返回第I个元素的引用。重载tuple的get函数是为了像处理tuple一样处理array。为此,头文件还使用定义的适当成员重载tuple_size和tuple_element type。
模板参数
I: array中元素的位置,第一个元素为0。
T: array中元素类型(通常可以从array隐式获得)。
N: array中元素的数量(通常可以从array隐式获得)。
函数参数
arr: 一个array容器。
返回值
array中指定位置元素的引用。
Example

// arrays as tuples
#include <iostream>
#include <array>
#include <tuple>

int main ()
{
  std::array<int,3> myarray = {10, 20, 30};
  std::tuple<int,int,int> mytuple (10, 20, 30);

  std::tuple_element<0,decltype(myarray)>::type myelement;  // int myelement

  myelement = std::get<2>(myarray);
  std::get<2>(myarray) = std::get<0>(myarray);
  std::get<0>(myarray) = myelement;

  std::cout << "first element in myarray: " << std::get<0>(myarray) << "\n";
  std::cout << "first element in mytuple: " << std::get<0>(mytuple) << "\n";

  return 0;
}

Output:

first element in myarray: 30
first element in mytuple: 10

复杂度
常数
迭代器有效性
不会变化。
数据竞争
array的第I个元素可能会被访问和修改。同步修改其他元素是安全的。
异常&安全
保证不抛出异常: 该函数永远不会抛出异常。

相关的操作符

前面已介绍

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值