广告位联系
返回顶部
分享到

C++20中的span容器及用法总结

C语言 来源:互联网 作者:佚名 发布时间:2023-03-05 08:22:02 人浏览
摘要

一.span容器 span是 C++20 中引入的一个新的标准容器,它用于表示连续的一段内存区间,类似于一个轻量级的只读数组容器。 span是一个轻量级的非拥有式容器,它提供了对连续内存的引用

一.span容器

span 是 C++20 中引入的一个新的标准容器,它用于表示连续的一段内存区间,类似于一个轻量级的只读数组容器。

span 是一个轻量级的非拥有式容器,它提供了对连续内存的引用。 span 的主要用途是作为函数参数,可以避免不必要的内存拷贝,并且可以防止悬垂指针和空指针引用的问题。

它的定义在头文件 <span> 中,并位于 std 命名空间中。span 包含了一个指向连续内存区域的指针以及它所占用的大小,可以通过它来访问这个内存区域中的元素。

span 主要用于以下场景:

  • 作为函数的参数,用于指示函数需要处理的数据范围;
  • 作为类的成员变量,用于表示对象所管理的内存区域;
  • 作为数组的视图,用于访问数组的一部分

二.span的用法

下面是几种 span 的用法示例:

1.将数组转换为 span:

1

2

int arr[] = {1, 2, 3, 4, 5};

span<int> s(arr, 5);

        这里将一个整型数组 arr 转换为 span 类型,并使用数组首地址和元素个数作为参数。

2.使用 span 来遍历一个容器:

1

2

3

4

vector<int> vec = {1, 2, 3, 4, 5};

for (auto&& x : span(vec)) {

    cout << x << " ";

}

这里使用 span(vec) 来构造一个 span 对象,遍历其中的元素并输出。

3.使用 span 来获取子序列:

1

2

3

int arr[] = {1, 2, 3, 4, 5};

span<int> s(arr, 5);

auto s1 = s.subspan(1, 3);

这里将一个 span 对象 s 分割为从第 1 个元素开始,长度为 3 的子序列,并将结果存储到 s1 中。

4.将 span 转换为其他容器类型:

1

2

3

int arr[] = {1, 2, 3, 4, 5};

span<int> s(arr, 5);

vector<int> vec(s.begin(), s.end());

这里使用 s.begin() 和 s.end() 将 span 对象 s 转换为迭代器范围,并使用这个迭代器范围构造一个 vector 容器 vec。

 

三.span的底层原理

下面为 span的简化版源码,用于展示其基本实现:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

template<typename T, std::size_t Extent = std::dynamic_extent>

class span {

public:

    // 定义迭代器类型

    using iterator = T*;

    using const_iterator = const T*;

  

    // 构造函数

    constexpr span() noexcept : data_(nullptr), size_(0) {}

    constexpr span(T* ptr, std::size_t count) : data_(ptr), size_(count) {}

    template <std::size_t N>

    constexpr span(T(&arr)[N]) noexcept : data_(arr), size_(N) {}

    template <typename Container>

    constexpr span(Container& c) noexcept : data_(c.data()), size_(c.size()) {}

  

    // 拷贝构造函数和拷贝赋值运算符

    constexpr span(const span& other) noexcept = default;

    span& operator=(const span& other) noexcept = default;

  

    // 访问元素和迭代器操作

    constexpr T* data() const noexcept { return data_; }

    constexpr std::size_t size() const noexcept { return size_; }

    constexpr bool empty() const noexcept { return size_ == 0; }

    constexpr T& operator[](std::size_t idx) const { return data_[idx]; }

    constexpr T& front() const { return data_[0]; }

    constexpr T& back() const { return data_[size_-1]; }

    constexpr iterator begin() const noexcept { return data_; }

    constexpr iterator end() const noexcept { return data_ + size_; }

    constexpr const_iterator cbegin() const noexcept { return data_; }

    constexpr const_iterator cend() const noexcept { return data_ + size_; }

  

private:

    T* data_;  // 元素指针

    std::size_t size_;  // 元素数量

};

具体实现方式是通过指针来引用连续的一段内存,从而实现 span 的基本功能。由于 span 没有实际的内存所有权,所以它不能拥有或释放内存。它只是提供了对现有内存块的访问。

标准库中的 span 还提供了一些其他的功能,比如对子区间的切片和子区间的迭代器等。实际的实现可能会更加复杂,但其基本的思想是一致的。

四.span 与 array ,vector ,数组指针 的区别

1. span 与 array ,vector的区别

span 是 C++20 中新增的一个轻量级容器,用于表示一段连续的内存区域,它不负责管理内存空间,也不会拥有所指向内存的所有权,只是提供一种方便的方式来操作内存区域,因此可以看做是一个只读的“裸指针”。

与 array 和 vector 相比,span 的主要区别在于它不拥有自己的存储空间,而是引用了另一个数组或容器的内存空间。因此,当我们需要使用一个连续的内存块时,可以使用 span 来代替 array 或 vector。

具体来说,array 是一个固定大小的数组容器,其大小在编译时就确定了,不能动态改变。vector 是一个动态增长的数组容器,可以动态分配内存,并在需要时扩大容量。而 span 是一个非拥有型的容器,可以看作是一个指向连续内存区域的引用,可以指向任何类型的元素。

在使用方面,array 和 vector 可以用来存储数据,并通过下标或迭代器来访问其中的元素;span 则更多地用来表示一段内存区域,并提供类似于迭代器的操作来访问其中的元素(就是 只读),如 begin、end、rbegin、rend 等。

总之,span、array 和 vector 三者各有所长,可以根据实际需求来选择使用。

2. span 与 数组指针的区别

在C++中,数组和指针是密不可分的,它们常常被一起使用。然而,数组和指针不是相同的东西,它们有自己的属性和限制。同样地,span和指针也有很多区别,这里列举几点:

span是一个封装了数组指针和长度的轻量级容器,它提供了对数组的安全访问。指针只是一个指向内存位置的地址,没有长度信息。因此,使用指针时需要显式地传递长度信息,否则可能会导致缓冲区溢出等问题。

span支持范围操作,它可以使用STL中的算法和其他支持范围操作的库进行操作。指针只能通过指针运算和下标操作来访问和操作数据。

span是可传递性的,可以传递到函数中作为参数,而指针不能。这是因为在函数中传递指针时,我们必须显式地传递指针所指向的内存块的大小,否则函数无法确定内存块的大小。

span是一个类模板,可以指定数据类型和长度类型。指针只能指向特定类型的数据。

总的来说,span比指针更安全,更灵活,更易于使用,是一种更好的数组容器类型。

五.span的优点

std::span 的主要优点如下:

轻量级:std::span 本身只是一个轻量级的非拥有式容器,没有自己的内存管理,因此可以在不分配内存的情况下轻松地传递和操作数据。同时,std::span 的内存布局与原始数组相同,因此不需要进行数据的复制或重排。

安全性:std::span 具有边界检查机制,可以避免访问越界等错误,从而提高代码的安全性。

可组合性:std::span 可以与其他容器类型进行组合,例如可以从 std::vector 或 std::array 中创建 std::span,或将 std::span 转换为 std::vector 或 std::array。

易于扩展:由于 std::span 只是一个非拥有式容器,因此可以轻松地将其用作接口的一部分,并以此扩展接口的功能。

总之,std::span 是一个非常实用的工具,可以方便地对数据进行访问和处理,同时也可以提高代码的可读性、可维护性和安全性。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/Appleeatingboy/article/details/129314624
相关文章
  • C++实现读写ini配置文件的代码
    1.概述 配置文件的读取是每个程序必备的功能,配置文件的格式多种多样,例如:ini格式、json格式、xml格式等。其中属ini格式最为简单,且
  • C++20中的span容器及用法总结
    一.span容器 span是 C++20 中引入的一个新的标准容器,它用于表示连续的一段内存区间,类似于一个轻量级的只读数组容器。 span是一个轻量级
  • C++20中的std::span介绍
    span就是一个连续对象存储的观察者。类似std::string_view是string的观察者。 连续的存储,不一定是数组。例如: 1 2 3 4 5 6 7 8 zero(char (arr) [10]
  • C++11之std::future对象的使用以及说明

    C++11之std::future对象的使用以及说明
    std::future介绍 在前面几篇文章中基本都用到thread对象,它是C++11中提供异步创建多线程的工具。 但是我们想要从线程中返回异步任务结果,
  • C语言中#define在多行宏定义出错的原因及分析
    C语言中#define在多行宏定义出错的原因 1.第一种错误 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #includestdio.h #define echange(a,b) {\/*宏定义中允许包含多行命
  • vs2022 x64 C/C++和汇编混编(案例代码)

    vs2022 x64 C/C++和汇编混编(案例代码)
    vs2022环境x64 C/C++和汇编混编 vs64位程序不支持__asm内嵌汇编,需要单独编写汇编源文件 示例如下 1、新建空的win32项目,新建main.cpp,示例代码
  • C语言中带返回值的宏定义方式
    C语言中带返回值的宏定义 相信大家在实际工作中,一定有遇到需要编写一个宏定义,且希望它能带返回值的场景吧? 比如我之前就遇到一
  • OpenCV实现视频绿幕背景替换功能
    1、概述 案例:使用OpenCV实现视频绿幕背景替换 算法步骤: 1.初始化VideoCapture并使用其open方法加载视频 2.while循环加读取frame capture.read(fra
  • OpenCV通过透视变换实现矫正图像介绍

    OpenCV通过透视变换实现矫正图像介绍
    1、概述 案例:使用OpenCV将一张折射的图片给矫正过来 实现步骤: 1.载入图像 2.图像灰度化 3.二值分割 4.形态学操作去除噪点 5.轮廓发现
  • 一篇文章彻底搞懂C++常见容器

    一篇文章彻底搞懂C++常见容器
    1.概述 C++容器属于STL(标准模板库)中的一部分(六大组件之一),从字面意思理解,生活中的容器用来存放(容纳)水或者食物,东西,
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计