当前位置:   article > 正文

C++20 span_gsl::span

gsl::span

01 范围检查:span

span是对象的连续序列上的无所有权视图。1

类模板 span 所描述的对象能指代对象的相接序列,序列的首元素在零位置。 span 能拥有静态长度,该情况下序列中的元素数已知并编码于类型中,或拥有动态长度。
典型实现只保有二个成员:指向 T 的指针和大小。2

到2020年1月16日前,有3个span的开源版本。
微软实现了一个版本的span3微软版gsl目前有9个头文件。

独立头文件的兼容C ++ 11及更高版本的span实现4

span lite:适用于C ++ 98,C ++ 11和更高版本的C ++ 20跨度的单文件标头版本。5

span用来做范围检查。提供对一个连续元素序列(主要指内置数组)的访问能力。元素可用很多方式存储,包括存储在vector和内置数组中。类似于指针,一个span不拥有它指向的字符。在这一点上,它很像string_view和STL的迭代器对。
std::span可能采用合约来控制对范围错误的响应。span的范围检查几乎无额外性能代价。6

span能很好的解决内置数组退化和越界访问的问题。7

02 span demo

https://github.com/5455945/cpp_demo/blob/master/C%2B%2B20/span/span.cpp

#include <iostream>
// 这里的gsl::span是微软的一个开源实现
// https://github.com/microsoft/GSL/tree/master/include/gsl
#include <gsl/gsl>

using namespace std;

// 《C++语言导论》 P147 13.3 范围检查:span
void fpn(int* p, int n) { // p可以是一个内置数组
    for (int i = 0; i < n; i++) {
        p[i] = 1;
    }
}

void use(int x) {
    int a[100];  // 内置数组
    fpn(a, 100);       // 正确
    //fpn(a, 1000);      // 糟糕,范围越界,(0xC0000005: 写入位置 0x000000E546F00000 时发生访问冲突。)
    //fpn(a + 10, 100);  // fpn中产生范围错误,(Run-Time Check Failure #2 - Stack around the variable 'a' was corrupted.)
    //fpn(a, x);         // 可疑的,但看起来无事,(x>100,Run-Time Check Failure #2 - Stack around the variable 'a' was corrupted.)
}

void fs(gsl::span<int> p) {
    for (auto& x : p) {
        x = 2;
    }
}

void use_span(int x) {
    int a[100];
    fs(a);               // 隐式创建一个span<int>{a, 100}
    //fs({ a, 1000 });     // 错误:期待一个sapn
    //fs({ a + 10, 100 }); // 在fs中发生范围错误,(Run-Time Check Failure #2 - Stack around the variable 'a' was corrupted.)
    //fs({ a, x });        // 明显可疑,(x>100,Run-Time Check Failure #2 - Stack around the variable 'a' was corrupted.)
}

// C++核心准则边译边学-X.4:使用span解决数组退化和越界访问
// https://blog.csdn.net/craftsman1970/article/details/103217292
void traditional_array(int buffer[], size_t size)
{
    cout << "size=" << size << endl;
    for (int i = 0; i < int(size); ++i) {
        buffer[i] = i;
    }
    buffer[0] = int(size * 2);
    //buffer[size * 2] = int(size * 4);  // 传统数组越界访问
}

void span_array(gsl::span<int> buffer)
{
    cout << "size=" << buffer.size() << endl;
    int value = 0;
    for (auto it = buffer.begin(); it != buffer.end(); it++) {
        *it = value++;
    }
    buffer[0] = value++;
    //buffer[buffer.size() * 2] = value++; // span会触发断言
}

int main()
{
    int x = 105;
    use(x);
    use_span(x);

    int data[10]; // 内置数组
    for (size_t i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
        data[i] = 0;
    }
    // 使用数组传递参数
    traditional_array(data, 5);
    // 使用span传递参数
    span_array(data);

    gsl::span<int> sdata = data;
    for (auto v : sdata) {
        std::cout << v << ", ";
    }
    std::cout << std::endl;

    return 0;
}
  • 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
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

  1. 标准库头文件span ↩︎

  2. std::span ↩︎

  3. 准则支持库 ↩︎

  4. 为旧版编译器实现C ++ 20的单独头文件的span ↩︎

  5. span lite,适用于C++98,及更高版本的单独头文件实现的span ↩︎

  6. 《C++语言导论》第二版 P147 ↩︎

  7. C++核心准则边译边学-X.4:使用span解决数组退化和越界访问 ↩︎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/265613?site
推荐阅读
相关标签
  

闽ICP备14008679号