您现在的位置: 主页 > 嵌入式软件 > C/C++ > 现代C++核心指导中提到的 span<T> 类型到底是哪个?
本文所属标签:
为本文创立个标签吧:

现代C++核心指导中提到的 span<T> 类型到底是哪个?

来源:网络整理 网络用户发布,如有版权联系网管删除 2018-09-04 

span<T>就是在CppCon 2015里面提到的array_view<T>的新名称,它的主要作用有两个:

  • 解决传参时数组退化所导致的丢失数组尺寸的问题
  • 更容易地检查出因为范围(ranges)大小错误而产生的问题
-------------------------------------------------------------------------------------------------
举几个例子:
1. 给定一个int数组,如何设计一个函数为数组的所有元素+1?
(来自C++ Core Guidelines 条款P.7)
void increment1(int* p, int n)    // 容易出错
{
    for (int i = 0; i < n; ++i)
        ++p[i];
}

void use1(int m)
{
    const int n = 10;
    int a[n] = {};
    // ...
    increment1(a, m);   // 不慎将 n 错打为 m,或者设计者希望 m <= n
                        // 如果在 m > n 的情况下调用increment1呢?
    // ...
}
在这种情况下,只有在increment1访问p[10]时,错误才有可能产生。
这种情况下就可以使用span<int>:
void increment2(span<int> p)     // 改用span
{
    for (int& x : p)
        ++x;
}

void use2(int m)
{
    const int n = 10;
    int a[n] = {};
    // ...
    increment2({a, m});    // 不慎将 n 错打为 m,或者设计者希望 m <= n
    // ...
}
这样就能保证编译器在发现 m > n 的时候就能报错。
而且如果设计者希望increment作用于所有元素,可以这样:
void use3(int m)
{
    const int n = 10;
    int a[n] = {};
    // ...
    increment2(a);   // 无须指出元素个数
    // ...
}
-------------------------------------------------------------------------------------------------
2. 如何将一个数组里面的若干个元素复制到另一个数组里?
(来自C++ Core Guidelines 条款I.13)
你可能会这样做:
template <typename T>
void copy_n(const T* p, T* q, int n); // 从 p 里复制 n 个元素到 q
但是这样做存在两个问题:
  • 如果 q 的元素个数比 n 小呢?这样有部分无关内存会被重写。
  • 如果 p 的元素个数比 n 小呢?这样有部分无关内存会被读取。
任何一个问题都是未定义行为,而且是一个潜在的Bug。
这时就可以使用span:
template <typename T>
void copy(span<const T> p, span<T> r); // 复制 p 的所有元素到 q
-------------------------------------------------------------------------------------------------
3. 有一个Circle数组,如何使用一个draw函数打印所有的Circle对象?
(来自C++ Core Guidelines 条款I.13)
class Shape { /* ... */ };
class Circle : public Shape { /* ... */ }

void draw(Shape* p, int n);  // 参数是 Shape* 而不是 Circle*
Circle arr[10];
// ...
draw(arr, 10); // 调用了参数为Shape* 的函数,可能不是调用者的本意
这种调用有两个问题:
  1. 无法确定 n 是否应该是 p 的大小。(虽然有很大可能,但函数声明无法保证这一点)
  2. Circle[10] 先被隐式地转换成了 Circle* ,又被转换成了 Shape* ,没有任何警告。
在这种情况下使用span可以预防这样的隐式转换:
void draw2(span<Circle>);
Circle arr[10];
// ...
draw2(span<Circle>(arr));  // 自动推导元素个数
draw2(arr);                // 自动推导元素类型与个数

void draw3(span<Shape>);
draw3(arr);                // 错误:无法将 Circle[10] 转换为 span<Shape>
-------------------------------------------------------------------------------------------------
4. 如何从任意一段区间(元素类型为X)搜索某个X类特定值?
(来自C++ Core Guidelines 条款F.24)
X* find(span<X> r, const X& v);    // 从 r 里搜寻 v

vector<X> vec;
// ...
auto p = find({vec.begin(), vec.end()}, X{});  // 在vec里搜寻值为 X{} 的元素
span对象显式地表示了一段区间,它并不具有这段区间元素的所有权,可以按值传递。
-------------------------------------------------------------------------------------------------
最后放上微软的span实现:GSL/span.h at master Microsoft/GSL GitHub

              查看评论 回复



嵌入式交流网主页 > 嵌入式软件 > C/C++ > 现代C++核心指导中提到的 span&lt;T&gt; 类型到底是哪个?
 一个 数组 问题

"现代C++核心指导中提到的 span&lt;T&gt; 类型到底是哪个?"的相关文章

网站地图

围观()