C++ 20新特性之std::span

💡 如果想阅读最新的文章,或者有技术问题需要交流和沟通,可搜索并关注微信公众号“希望睿智”。

为什么要引入std::span

        在C++中,我们经常需要传递数组或容器的一部分给函数进行处理。通常的做法是使用指针和长度来表示数组的一部分,但这可能导致越界和难以维护的代码。C++ 20中新引入的std::span,则提供了一种更安全、更直观的方式来处理这种情况。

        实际上,std::span是一个非常实用的容器适配器,用于表示连续的内存区域。它并不直接拥有数据,而是提供了一种访问现有数组或容器元素的方式,增强了代码的灵活性和泛型性。std::span可以看作是对指针和长度对的一个类型安全、范围安全的封装,特别适合用于算法和接口设计中,以提高代码的可重用性和安全性。

std::span基础

        std::span<T>是一个模板类,其中T是元素的类型,它可以通过数组、标准库容器或其他任何提供迭代器的对象来构造。std::span有两个关键属性:一个是指向连续数据元素的指针,另一个表示元素数量的size_t值。这使得它可以安全地访问并操作数据范围内的元素,而不需要知道数据的具体存储方式。std::span提供了类似数组的接口,允许我们通过索引访问元素,并提供了size()、empty()、begin()、end()等成员函数来获取关于数据的信息。

        std::span的主要特点如下。

        1、非拥有性。std::span不拥有它所引用的数据,它只是一个视图。

        2、类型安全。std::span知道它所引用的数据的类型。

        3、边界检查。由于std::span知道数据的大小,因此可以在访问时执行边界检查。

        4、灵活性。std::span可以与数组、std::vector、std::array等容器一起使用。

std::span的使用

        创建一个std::span的对象有好几种方法,包括:默认构造函数、从数组构造、从指针和大小构造、从一对指针构造、从容器构造、具有指定大小的构造等。访问std::span中的元素有三种方法,分别为:通过索引访问元素、带有边界检查的访问元素方法at()、访问第一个和最后一个元素的front()/back()。

        下面的示例代码演示了这些方法的使用,可以作为参考。

#include <iostream>
#include <span>
#include <vector>
using namespace std;

int main()
{
    // 默认构造函数
   span<int> emptySpan;
   // 输出:0
   cout << emptySpan.size() << endl;

    // 从数组构造
    int pNumber[]{10, 20, 30, 40, 50};
   span<int> arraySpan(pNumber);
   // 输出:10
   cout << arraySpan.front() << endl;

    // 从指针和大小构造
    int* pData = pNumber;
   span<int> ptrAndSizeSpan(pData, 3);
   // 输出:30
   cout << ptrAndSizeSpan[2] << endl;

    // 从一对指针(首尾指针)构造
   span<int> pairPtrSpan(pData, pData + 2);
   // 输出:20
   cout << pairPtrSpan[1] << endl;

    // 从容器构造
   vector<int> vctNumber = {66, 77, 88};
   span<int> containerSpan(vctNumber);
   // 输出:88
   cout << containerSpan.back() << endl;

    // 具有指定大小的构造(静态大小)
    span<int, 3> staticSizeSpan(pNumber);
    // 输出:20
    cout << staticSizeSpan[1] << endl;

    return 0;
}

        除了以上这些接口,std::span还可以用来生成一个新的std::span。subspan()函数可生成一个新的span,表示当前span中的一部分。first()函数返回span的前count个元素组成的span,last()函数返回span的后count个元素组成的span。

#include <iostream>
#include <span>
#include <vector>
using namespace std;

int main()
{
    vector<int> numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    span<int> fullSpan(numbers);

    // 使用subspan()方法生成新span(从索引3开始,长度为4的新span)
    span<int> subSpan = fullSpan.subspan(3, 4);
    // 输出:3 4 5 6
    for(int num : subSpan)
        cout << num << " ";
    cout << endl;

    // 使用first()方法获取前几个元素的span
    span<int> span1 = fullSpan.first(3);
    // 输出:0 1 2
    for(int num : span1)
        cout << num << " ";
    cout << endl;

    // 使用last()方法获取后几个元素的span
    span<int> span2 = fullSpan.last(4);
    // 输出:6 7 8 9
    for(int num : span2)
        cout << num << " ";
    cout << endl;

    return 0;
}

注意事项

        1、std::span不拥有数据,因此不能延长其生命周期。当底层数组或容器销毁时,std::span变为悬挂引用,使用它将导致未定义行为。

        2、尽管std::span提供了丰富的接口,但它不支持直接改变大小或直接插入/删除元素,因为它是对现有数据的视图。

  • 44
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

希望_睿智

您的鼓励将是我创作的最大动力!

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

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

打赏作者

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

抵扣说明:

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

余额充值