0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

​数组和C++ std::array详解

冬至子 来源:iDoitnow 作者:艰默 2023-07-19 11:02 次阅读

1. 数组和std::array

std::arrayC++容器库提供的一个固定大小数组的容器。其与内置的数组相比,是一种更安全、更容易使用的数组类型。std::array在头文件中定义,其声明如下:

template<
    class T,
    std::size_t N
> struct array; //C++11 起

std::array是一个聚合类型,其语义等同于保有一个C语言风格数组T[N]作为其唯一非静态数据成员的结构体,但其不同于C数组的是它不会自动退化为T*。同时该结构体结合了C风格数组的性能、可访问性和容器的优点(可获取大小、支持赋值和随机访问等)。

2. array的用法

2.1 成员函数

2.1.1 隐式定义的成员函数

1.jpg

聚合初始化就是从初始化器列表来初始化聚合体,其也是列表初始化的一种方式。

std::array< int, 3 > a = {1,2,3};
std::array< int, 3 > b;
b = a;  //将a中的每个元素重写到b中,使用operator=时候需要确保a b两个容器长度相等,否则编译失败

2.1.2 元素访问

at

at用于访问指定的元素, 同时进行越界检查 ,该函数返回位于指定位置pos的元素的引用,如果pos不在容器的范围内,则抛出std::out_of_range异常。其函数声明如下:

reference at( size_type pos ); //C++17 前
constexpr reference at( size_type pos ); //C++17 起
const_reference at( size_type pos ) const; //C++14 前
constexpr const_reference at( size_type pos ) const; //C++14 起

其具体用法如下:

std::array< int,3 > data = { 1, 2, 3};

std::cout<

operator[]

operator[]与at功能相同,即用来访问指定的元素,但其与at不同的是:operator[]不进行边界的检查。其函数声明如下所示:

reference operator[]( size_type pos ); //C++17 前
constexpr reference operator[]( size_type pos ); //C++17 起
const_reference operator[]( size_type pos ) const; //C++14 前
constexpr const_reference operator[]( size_type pos ) const; //C++14 起

:通过operator[]符访问不存在的元素是未定义行为。

front

front用于访问容器的第一个元素,其返回值为容器首元素的引用,其函数原型如下:

reference front(); //C++17 前
constexpr reference front(); //C++17 起
const_reference front() const; //C++14 前
constexpr const_reference front() const; //C++14 起

:在空容器上对 front 的调用是未定义的。

back

back主要功能是用来访问容器最后一个元素,其返回值为容器最后一个元素的引用,其函数原型如下所示:

reference back(); //C++17 前
constexpr reference back(); //C++17 起
const_reference back() const; //C++14 前
constexpr const_reference back() const; //C++14 起

:在空容器上调用 back 导致未定义行为。

data

data可以直接访问容器底层数组,其返回值为指向作为元素存储工作的底层数组的指针。其函数声明如下:

T* data() noexcept; //C++11 起, C++17 前
constexpr T* data() noexcept; //C++17 起
const T* data() const noexcept; //C++11 起, C++17 前
constexpr const T* data() const noexcept; //C++17 起

其返回的指针使得范围[ data(), data() + size() )始终是合法范围。

2.2.3 迭代器

begin、end和cbegin、cend

begin和cbegin返回指向deque首元素的迭代器,end和cend返回指向deque末元素后一元素的迭代器。其函数声明如下:

iterator begin() noexcept; //C++17 前
constexpr iterator begin() noexcept; //C++17 起
const_iterator begin() const noexcept; //C++17 前
constexpr const_iterator begin() const noexcept; //C++17 起
const_iterator cbegin() const noexcept; //C++17 前
constexpr const_iterator cbegin() const noexcept; //C++17 起

iterator end() noexcept; //C++17 前
constexpr iterator end() noexcept; //C++17 起
const_iterator end() const noexcept; //C++17 前
constexpr const_iterator end() const noexcept; //C++17 起
const_iterator cend() const noexcept; //C++17 前
constexpr const_iterator cend() const noexcept; //C++17 起

如果array为空,则返回的迭代器将等于end或cend。end和cend指向deque末元素后一元素的迭代器,该元素的表现为占位符,试图访问它将导致未定义行为。

图片

rbegin、rend和crbegin、crend

rbegin和crbegin返回指向array首元素的逆向迭代器。它对应非逆向array的末元素,若array为空,则返回的迭代器等于rend或crend。rend和crend返回指向逆向deque末元素后一元素的逆向迭代器,它对应非逆向array首元素的前一元素,此元素表现为占位符,试图访问它导致未定义行为。它们的声明如下:

reverse_iterator rbegin() noexcept; //C++17 前
constexpr reverse_iterator rbegin() noexcept; //C++17 起
const_reverse_iterator rbegin() const noexcept; //C++17 前
constexpr const_reverse_iterator  rbegin() const noexcept; //C++17 起
const_reverse_iterator crbegin() const noexcept; //C++17 前
constexpr const_reverse_iterator crbegin() const noexcept; //C++17 起

reverse_iterator rend(); //C++11 前
reverse_iterator rend() noexcept; //C++11 起
const_reverse_iterator rend() const; //C++11 前
const_reverse_iterator rend() const noexcept; //C++11 起
const_reverse_iterator crend() const noexcept; //C++11 起

图片

2.2.4 容量

empty

empty用来检查容器是否为空,若为空则返回true,否则为false。其函数声明如下:

constexpr bool empty() const noexcept; //C++11 起,C++20 前
[[nodiscard]] constexpr bool empty() const noexcept; //C++20 起

其底层实现就是检查容器是否无元素,即判断是否begin() == end()

size

size函数返回容器中元素数量,即std::distance(begin(), end())。其函数声明如下:

constexpr size_type size() const noexcept; //C++11 起

max_size

max_size函数返回根据系统或库实现限制的容器可保有的元素最大数量,即对于最大容器的 std::distance(begin(), end())。其函数声明为:

constexpr size_type max_size() const noexcept; //C++11 起

:因为每个 std::array 都是固定大小容器,故 max_size 返回的值等于 N (亦为size所返回的值)

2.2.5 修改器

fill

fill函数原型如下所示:

void fill( const T& value ); //C++11 起, C++20 前
constexpr void fill( const T& value ); //C++20 起

fill函数主要用于以指定值填充容器,即将定值 value 赋给容器中的所有元素。

具体用法示例如下:

std::array< int, 3 > arr = {1, 2, 3};
arr.fill(1); // arr = {1, 1, 1}

swap

swap函数的主要作用是交换两个array容器的内容,其与deque的swap不同的是不导致迭代器和引用关联到别的容器。其函数声明如下:

void swap( array& other ) noexcept(); //C++11 起, C++20 前
constexpr void swap( array& other ) noexcept(); //C++20 起

其用法示例如下图所示:

std::array< int, 3 > a1{1, 2, 3}, a2{4, 5, 6};

auto it1 = a1.begin(); //*it1 = 1
auto it2 = a2.begin(); //*it2 = 4

int &ref1 = a1[1]; // ref1 = 2
int &ref2 = a2[1]; // ref1 = 5

std::cout < < *it1 < < ' ' < < *it2 < < ' ' < < ref1 < < ' ' < < ref2 < < 'n';
// 打印结果为1 4 2 5

a1.swap(a2);

// 此时a1 = {4, 5, 6},a2 = {1, 2, 3}
std::cout < < *it1 < < ' ' < < *it2 < < ' ' < < ref1 < < ' ' < < ref2 < < 'n';
// 打印结果为4 1 5 2

/*注:
     交换后迭代器与引用保持与原 array 关联,
     例如it1仍指向元素 a1[0] ,ref1仍指代 a1[1] */

2.2 非成员函数

operator==,!=,<,<=,>,>=,<=>(std::array)

C++提供operator==,!=,<,<=,>,>=,<=>(std::array)非成员函数用来比较两个array的大小,相关函数及函数声明如下:

//1. ==
//返回值:在 array 内容相等时返回 true,否则返回 false
template< class T, std::size_t N >
bool operator==( const std::array< T, N >& lhs,
                 const std::array< T, N >& rhs ); //C++20 前

template< class T, std::size_t N >
constexpr bool operator==( const std::array< T, N >& lhs,
                           const std::array< T, N >& rhs ); //C++20 起

//2. !=
//返回值:在 array 内容不相等时返回 true,否则返回 false
template< class T, std::size_t N >
bool operator!=( const std::array< T, N >& lhs,
                 const std::array< T, N >& rhs ); //C++20 前

//3. < 
//返回值:在 lhs 的内容按字典序小于 rhs 的内容时返回 true,否则返回 false
template< class T, std::size_t N >
bool operator< ( const std::array< T, N >& lhs,
                const std::array< T, N >& rhs ); //C++20 前

//4. <=
//返回值:在 lhs 的内容按字典序小于或等于 rhs 的内容时返回 true,否则返回 false
template< class T, std::size_t N >
bool operator<=( const std::array< T, N >& lhs,
                 const std::array< T, N >& rhs ); //C++20 前

//5. >
//返回值:在 lhs 的内容按字典序大于 rhs 的内容时返回 true,否则返回 false
template< class T, std::size_t N >
bool operator >( const std::array< T, N >& lhs,
                const std::array< T, N >& rhs ); //C++20 前

//6. >=
//返回值:在 lhs 的内容按字典序大于或等于 rhs 的内容时返回 true,否则返回 false
template< class T, std::size_t N >
bool operator >=( const std::array< T, N >& lhs,
                 const std::array< T, N >& rhs ); //C++20 前

//7. <= >
//返回值:lhs 与 rhs 中的首对不等价元素的相对顺序,如果有这种元素;否则是 lhs.size() <= > rhs.size()。
template< class T, std::size_t N >
constexpr operator<= >( const std::array< T, N >& lhs,
                                       const std::array< T, N >& rhs ); //C++20 起
  • 1,2中会检查lhs和rhs的内容是相等,即他们是否拥有相同数量的元素且lhs中每个元素与rhs的相同位置元素比较相等。同时函数中T 必须符合 可相等比较(EqualityComparable) 的要求

  • 3-6中按照字典比较lhs和rhs的内容,其内部等价于调用std::lexicographical_compare函数进行比较。同时函数中T 必须符合[ 可小于比较(LessThanComparable) 的要求。

  • 7中也是按字典序比较lhs和rhs的内容。其内部等价于调用std::lexicographical_compare_three_way进行比较。返回类型同合成三路比较的结果类型。其逻辑大致如下:

    lhs < rhs ? std::weak_ordering::less :
    rhs < lhs ? std::weak_ordering::greater :
                std::weak_ordering::equivalent
    //注:通常情况下less对应的是-1,greater对应1,equivalent对应0
    

    lhs与rhs中的首对不等价元素的相对顺序,如果有这种元素;否则是lhs.size() <=> rhs.size()

其具体的应用示例如下所示:

std::array< int, 3 > alice{1, 2, 3};
std::array< int, 3 > bob{7, 8, 9};
std::array< int, 3 > eve{1, 2, 3};

std::cout < < std::boolalpha;

// 比较不相等的容器
std::cout < < "alice == bob returns " < < (alice == bob) < < 'n';
std::cout < < "alice != bob returns " < < (alice != bob) < < 'n';
std::cout < < "alice <  bob returns " < < (alice < bob) < < 'n';
std::cout < < "alice <= bob returns " < < (alice <= bob) < < 'n';
std::cout < < "alice >  bob returns " < < (alice > bob) < < 'n';
std::cout < < "alice >= bob returns " < < (alice >= bob) < < 'n';

std::cout < < 'n';

// 比较相等的容器
std::cout < < "alice == eve returns " < < (alice == eve) < < 'n';
std::cout < < "alice != eve returns " < < (alice != eve) < < 'n';
std::cout < < "alice <  eve returns " < < (alice < eve) < < 'n';
std::cout < < "alice <= eve returns " < < (alice <= eve) < < 'n';
std::cout < < "alice >  eve returns " < < (alice > eve) < < 'n';
std::cout < < "alice >= eve returns " < < (alice >= eve) < < 'n';

输出结果为

alice == bob returns false
alice != bob returns true
alice <  bob returns true
alice <= bob returns true
alice >  bob returns false
alice >= bob returns false
 
alice == eve returns true
alice != eve returns false
alice <  eve returns false
alice <= eve returns true
alice >  eve returns false
alice >= eve returns true

std::get(std::array)

std::get(std::array)可以用来访问array的一个元素,其函数声明如下:

template< std::size_t I, class T, std::size_t N >
T& get( std::array< T,N >& a ) noexcept; //C++11 起, C++14 前

template< std::size_t I, class T, std::size_t N >
constexpr T& get( std::array< T,N >& a ) noexcept; //C++14 起

template< std::size_t I, class T, std::size_t N >
T&& get( std::array< T,N >&& a ) noexcept; //C++11 起, C++14 前

template< std::size_t I, class T, std::size_t N >
constexpr T&& get( std::array< T,N >&& a ) noexcept; //C++14 起 

template< std::size_t I, class T, std::size_t N >
const T& get( const std::array< T,N >& a ) noexcept; //C++11 起, C++14 前

template< std::size_t I, class T, std::size_t N >
constexpr const T& get( const std::array< T,N >& a ) noexcept; //C++14 起

template< std::size_t I, class T, std::size_t N >
const T&& get( const std::array< T,N >&& a ) noexcept; //C++11 起, C++14 前

template< std::size_t I, class T, std::size_t N >
constexpr const T&& get( const std::array< T,N >&& a ) noexcept; //C++14 起

其主要作用是从a中提取第I个元素.I必须是范围 [0, N) 中的整数值。与at()operator[]相反,这在编译时强制。该函数的返回值为a中第I元素的引用。

其具体的用法如下:

std::array< int, 3 > arr;

// 设置值:
std::get< 0 >(arr) = 1;
std::get< 1 >(arr) = 2;
std::get< 2 >(arr) = 3;

// 获取值:
std::cout < < "(" < < std::get< 0 >(arr) < < ", " < < std::get< 1 >(arr)
  < < ", " < < std::get< 2 >(arr) < < ")n";
//输出结果为 (1, 2, 3)

std::swap(std::array)

std::swap(std::array)函数是为std::array特化std::swap 算法。其函数声明如下:

template< class T, std::size_t N >
void swap( std::array< T, N >& lhs,
           std::array< T, N >& rhs ); //C++11 起, C++17template< class T, std::size_t N >
void swap( std::array< T, N >& lhs,
           std::array< T, N >& rhs ) noexcept(); //C++17 起, C++20template< class T, std::size_t N >
constexpr void swap( std::array< T, N >& lhs,
                     std::array< T, N >& rhs ) noexcept(); //C++20

交换 lhsrhs 的内容。调用lhs.swap(rhs)。其具体用法如下:

std::array< int, 3 > a1{1, 2, 3}, a2{4, 5, 6};

auto it1 = a1.begin(); //*it1 = 1
auto it2 = a2.begin(); //*it2 = 4

int &ref1 = a1[1]; // ref1 = 2
int &ref2 = a2[1]; // ref1 = 5

std::cout < < *it1 < < ' ' < < *it2 < < ' ' < < ref1 < < ' ' < < ref2 < < 'n';
// 打印结果为1 4 2 5

std::swap(a1, a2);

// 此时a1 = {4, 5, 6},a2 = {1, 2, 3}
std::cout < < *it1 < < ' ' < < *it2 < < ' ' < < ref1 < < ' ' < < ref2 < < 'n';
// 打印结果为4 1 5 2

std::to_array

std::to_array函数声明如下:

template< class T, std::size_t N >
constexpr std::array< std::remove_cv_t< T >, N > to_array(T (&a)[N]); //C++20 起

template< class T, std::size_t N >
constexpr std::array< std::remove_cv_t< T >, N > to_array(T (&&a)[N]); //C++20 起

std::to_array函数可以从一维内建数组 a 创建 std::array 对象,从 a 的对应元素复制初始化 std::array 的元素。不支持复制或移动多维内建数组。其具体用法如下:

#include < array >
#include < iostream >

int main()
{
  // 复制字符串字面量
  auto a1 = std::to_array("foo");
  static_assert(a1.size() == 4);

  // 推导元素类型和长度
  auto a2 = std::to_array({0, 2, 1, 3});

  // 推导长度而元素类型指定
  // 发生隐式转换
  auto a3 = std::to_array< long >({0, 1, 3});

  auto a4 = std::to_array< std::pair< int, float >>(
    {{3, .0f}, {4, .1f}, {4, .1e23f}});

  // 创建不可复制的 std::array
  auto a5 = std::to_array({std::make_unique< int >(3)});

  // 错误:不支持复制多维数组
  // char s[2][6] = { "nice", "thing" };
  // auto a6 = std::to_array(s);
}

std::tuple_size

std::tuple_size(std::array)函数的声明如下:

template< class T, std::size_t N >
struct tuple_size  std::array< T, N > > :
    std::integral_constant< std::size_t, N >   //C++11 起
{ };

其提供作为编译时常量表达式访问std::array中元素数量的方法。用法示例如下:

#include < iostream >
#include < array >
 
template< class T >
void test(T t)
{
    int a[std::tuple_size< T >::value]; // 能用于编译时
    std::cout < < std::tuple_size< T >::value < < 'n';
}
 
int main()
{
    std::array< float, 3 > arr;
    test(arr); //输出 3
}

std::tuple_element

std::tuple_element函数主要用来获得 array 元素的类型,其声明如下:

template< std::size_t I, class T, std::size_t N >
struct tuple_element I, std::array< T, N > >; //C++11 起

其使用类 tuple 接口,提供 array 元素类型的编译时带下标访问。具体使用方法如下:

// 定义 array 并获取位于位置 0 的元素类型
std::array< int, 10 > data {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
using T = std::tuple_element< 0, decltype(data) >::type; // int

3. 总结

数组std::array的优劣:

优点

  • 无开销随机访问。
  • 快速遍历;适合线性搜索。

劣势

  • 如果元素类型具有较高的复制/分配成本,则可能会变慢(重新排序元素需要复制/移动它们)。
  • 在使用array容器的时候,其size必须是常量表达式(即编译时已知)。
  • 不支持大小更改操作(调整大小、插入、擦除等)。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    38

    文章

    7413

    浏览量

    163466
  • 交换机
    +关注

    关注

    20

    文章

    2606

    浏览量

    99000
  • C语言
    +关注

    关注

    180

    文章

    7588

    浏览量

    135736
  • C++语言
    +关注

    关注

    0

    文章

    147

    浏览量

    6948
  • 迭代器
    +关注

    关注

    0

    文章

    43

    浏览量

    4294
收藏 人收藏

    评论

    相关推荐

    C语言—数组详解

    介绍C语言数组的知识点。
    的头像 发表于 05-19 10:15 6224次阅读

    鸿蒙c++模板开发详解

    鸿蒙c++模板开发详解
    发表于 09-11 15:28

    C++教程之数组

    C++教程之数组 新版的成绩管理系统编辑某同学的7门功课成绩分别为:88,89,90,75,76,64,95。设计一个程序求其平均成绩,并增加查询功能:即用户选择1
    发表于 05-15 17:59 45次下载

    C++ 语言命令详解(第二版)

    电子发烧友网站提供《C++ 语言命令详解(第二版).txt》资料免费下载
    发表于 07-28 13:06 0次下载

    C++实验 数组的应用

    C++实验 数组的应用
    发表于 12-30 15:04 0次下载

    C++语言入门教程之C++语言程序设计数组的详细资料概述免费下载

    本文档的主要内容详细介绍的是C++语言入门教程之C++语言程序设计数组的详细资料概述免费下载内容包括了:1 一维数组 2 二维数组 3 字符
    发表于 09-20 14:51 9次下载
    <b class='flag-5'>C++</b>语言入门教程之<b class='flag-5'>C++</b>语言程序设计<b class='flag-5'>数组</b>的详细资料概述免费下载

    C++程序设计教程之数组的详细资料说明

    本文档详细介绍的是C++程序设计教程之数组的详细资料说明主要内容包括了:1. 数组的概念,2. 一维数组的定义和引用,3. 二维数组的定义和
    发表于 03-14 14:48 10次下载
    <b class='flag-5'>C++</b>程序设计教程之<b class='flag-5'>数组</b>的详细资料说明

    图文详解C++虚表的剖析

    图文详解C++虚表的剖析
    的头像 发表于 06-29 14:23 2488次阅读
    图文<b class='flag-5'>详解</b>:<b class='flag-5'>C++</b>虚表的剖析

    图文详解C++的输出输入

    图文详解C++的输出输入
    的头像 发表于 06-29 14:53 3346次阅读
    图文<b class='flag-5'>详解</b>:<b class='flag-5'>C++</b>的输出输入

    C++中如何用虚函数实现多态

    01 — C++虚函数探索 C++是一门面向对象语言,在C++里运行时多态是由虚函数和纯虚函数实现的,现在我们看下在C++中如何用虚函数实现多态。先来看一段代码
    的头像 发表于 09-29 14:18 1652次阅读

    C++输入和输出的真实面目

    C++输入和输出 在C++std::cin、std::cout、std::cerr和std::
    的头像 发表于 09-29 15:22 1713次阅读

    C++入门之数组的概念

    上一篇文章我们介绍了C++中的迭代器,这篇文章将会介绍C++数组的概念,数组是一种和vector类似的数据结构,但是其在性能和灵活性上的权衡中选择了性能而放弃了一定的灵活性,其与ve
    的头像 发表于 03-17 14:14 652次阅读

    C++ std::tie函数的作用和用法

    C++std::tie函数的作用就是从元素引用中生成一个tuple元组,其在头文件中定义
    的头像 发表于 07-18 17:28 775次阅读

    动态数组C++ std::vector详解

    std::vector是C++的默认动态数组,其与array最大的区别在于vector的数组是动态的,即其大小可以在运行时更改。
    的头像 发表于 07-19 11:07 927次阅读

    C++数组名和数组拷贝详解

    C++数组间赋值不能直接通过数组名称 randy = sesame进行,因为数组名并不是指针,大部分情况下,编译器会隐式转换为指向数组首元素
    发表于 08-21 15:09 438次阅读
    <b class='flag-5'>C++</b><b class='flag-5'>数组</b>名和<b class='flag-5'>数组</b>拷贝<b class='flag-5'>详解</b>