C++11 <array>从入门到精通

一、引言

在C++编程中,数组是一种非常基础且重要的数据结构,它可以存储一组相同类型的元素。在C++11标准之前,开发者通常使用C风格数组来处理数组数据,但C风格数组存在一些问题,比如无法直接进行对象赋值、无法直接拷贝、数组名会退化为指针等,这些问题给开发带来了一定的困扰。为了解决这些问题,C++11标准引入了<array>头文件,提供了std::array容器,它是对C风格数组的改进和封装,具有更多的功能和安全性。本文将详细介绍std::array的相关知识,帮助小白从入门到精通。

二、std::array简介

2.1 定义

std::array是C++11标准库提供的一个固定大小的容器,用于存储特定类型的元素序列。它定义在<array>头文件中,是一个模板类,其基本定义如下:

template <typename T, std::size_t N>
class array;

其中,T表示数组中元素的类型,N表示数组的大小(即元素的个数)。

2.2 特点

  • 固定大小std::array的大小在创建时就已经确定,并且之后不能再改变。这种固定大小的特性使得std::array在内存使用上是高效的,因为它不需要动态分配内存或管理内存大小的变化。同时,由于其大小在编译时就已知,编译器可以进行一些优化,提高代码的执行效率。
  • 类型安全std::array强制类型检查,避免了C语言数组的类型不安全问题。它提供了at()函数来访问元素,同时提供边界检查以避免越界错误。
  • 内存连续std::array的元素在内存中是连续存储的,这使得它可以高效地访问元素。
  • 标准容器接口std::array提供了与std::vector类似的接口,如size()at()front()back()等,使得对数组的操作更加便捷和安全。

2.3 与C风格数组的区别

比较项std::arrayC风格数组
大小固定大小,在编译时确定大小可以是动态的,在运行时可以根据需要分配和调整
内存分配对象通常在栈上分配,生命周期与创建它的作用域相同可以在栈上或堆上分配,取决于数组的声明方式
安全性和边界检查提供边界检查,使用at()函数访问元素时,如果索引超出范围,程序会抛出异常不提供边界检查,程序员必须自己确保不会访问数组的非法区域
使用便捷性提供了许多便利的成员函数和迭代器,操作更加简单和直观操作相对较为基础,没有提供这些便利的函数和迭代器
与STL算法的兼容性作为STL容器,与STL算法完美兼容虽然也可以与一些STL算法结合使用,但通常需要额外的处理或转换

C++11 array与C风格数组对比

三、std::array的基本操作

3.1 包含头文件

要使用std::array,需要包含头文件<array>

#include <array>

3.2 声明与初始化

3.2.1 声明

声明一个std::array对象时,需要指定数组中的元素类型和数组的大小。声明的基本语法如下:

std::array<T, N> array_name;

其中,T是数组中元素的类型,N是数组的大小,必须是一个非负整数。

3.2.2 初始化
  • 默认值初始化:如果不提供任何初始值,std::array中的元素将使用其类型的默认值进行初始化。
std::array<int, 5> myArray; // 所有元素将被初始化为随机值
  • 列表初始化:可以使用花括号{}内的元素列表来初始化std::array。元素的数量必须与数组大小相匹配。
std::array<int, 5> myArray1 = {1, 2, 3, 4, 5};
std::array<int, 5> myArray2 {1, 2, 3, 4, 5};
  • 使用std::fill:可以使用std::fill函数来设置std::array中所有元素的值。
std::array<int, 5> myArray;
std::fill(myArray.begin(), myArray.end(), 0); // 所有元素设置为0

3.3 访问元素

可以使用下标操作符[]或者at()成员函数来访问std::array中的元素。at()函数会进行边界检查,如果索引越界,会抛出std::out_of_range异常。

#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    std::cout << "arr[0] = " << arr[0] << std::endl; // 使用下标操作符
    std::cout << "arr.at(2) = " << arr.at(2) << std::endl; // 使用at()函数

    try {
        std::cout << arr.at(5) << std::endl; // 超出范围,抛出异常
    } catch (const std::out_of_range& e) {
        std::cout << "Exception: " << e.what() << std::endl;
    }

    return 0;
}

C++11 array代码示例

3.4 遍历数组

std::array支持基于范围的for循环和迭代器,使得遍历元素变得非常方便。

3.4.1 基于范围的for循环
#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    return 0;
}
3.4.2 迭代器遍历
#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    for (auto it = arr.begin(); it != arr.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    return 0;
}

四、std::array的常用成员函数

4.1 size()

返回数组的大小,即元素的数量。

#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    std::cout << "Array size: " << arr.size() << std::endl;
    return 0;
}

4.2 front()back()

front()返回数组的第一个元素的引用,back()返回数组的最后一个元素的引用。

#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    std::cout << "First element: " << arr.front() << std::endl;
    std::cout << "Last element: " << arr.back() << std::endl;
    return 0;
}

4.3 data()

返回一个指向数组首个元素的指针。利用该指针,可以实现复制容器中所有元素等类似功能。

#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
    int* ptr = arr.data();
    for (int i = 0; i < arr.size(); ++i) {
        std::cout << *(ptr + i) << " ";
    }
    std::cout << std::endl;
    return 0;
}

4.4 fill(const T& value)

value这个值赋值给容器中的每个元素。

#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr;
    arr.fill(10);
    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    return 0;
}

4.5 swap(array& other)

交换两个数组的内容,但前提是它们具有相同的长度和类型。

#include <iostream>
#include <array>

int main() {
    std::array<int, 5> arr1 = {1, 2, 3, 4, 5};
    std::array<int, 5> arr2 = {5, 4, 3, 2, 1};
    arr1.swap(arr2);
    for (const auto& elem : arr1) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    for (const auto& elem : arr2) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    return 0;
}

五、std::array的高级应用

5.1 与STL算法结合使用

由于std::array完全兼容STL(标准模板库),可以与其他STL算法和容器类无缝协作。例如,可以使用std::sort对数组进行排序。

#include <iostream>
#include <array>
#include <algorithm>

int main() {
    std::array<int, 5> arr = {5, 3, 1, 4, 2};
    std::sort(arr.begin(), arr.end());
    for (const auto& elem : arr) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    return 0;
}

C++11 array高级应用

5.2 多维数组

可以使用std::array创建多维数组。例如,创建一个二维数组:

#include <iostream>
#include <array>

int main() {
    std::array<std::array<int, 3>, 2> arr = {
        { {1, 2, 3}, {4, 5, 6} }
    };
    for (const auto& row : arr) {
        for (const auto& elem : row) {
            std::cout << elem << " ";
        }
        std::cout << std::endl;
    }
    return 0;
}

六、std::array的优缺点和适用场景

6.1 优点

  • 类型安全std::array的大小是类型的一部分,因此不能创建大小不匹配的std::array对象,避免了一些潜在的错误。
  • 性能:由于大小在编译时已知,编译器可以对std::array进行更多的优化,提高代码的执行效率。
  • 接口丰富std::array提供了许多有用的成员函数,如fill()swap()等,这些函数让数组的操作更加便捷。

6.2 缺点

  • 固定大小std::array的大小在编译时就已确定,无法动态增加或减少元素,不适合需要动态调整数组大小的场景。
  • 初始化:如果std::array在全局或命名空间作用域中定义,并且没有显式初始化,则所有元素都将被零初始化,这在某些情况下可能是不必要的或不方便的。

6.3 适用场景

当需要使用固定大小的数组,并且对性能和安全性有较高要求时,std::array是一个很好的选择。例如,在数学和科学计算中,表示向量和矩阵;在图形编程中,表示像素数据、纹理和颜色等。

七、总结

std::array是C++11引入的一个非常有用的容器,它结合了C风格数组的性能和可访问性以及容器的优点,提供了一种更安全、更灵活的方式来处理固定大小的数组。通过本文的介绍,相信小白们已经对std::array有了更深入的了解,能够在实际编程中熟练使用它。希望大家在使用std::array的过程中,能够充分发挥其优势,提高编程效率和代码质量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码事漫谈

感谢支持,私信“已赏”有惊喜!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值