12 June 2022

C++ 核心指南目录

理由

不正式的/不明确的范围,容易导致错误。

例子

X* find(span<X> r, const X& v);    // find v in r

vector<X> vec;
// ...
auto p = find({vec.begin(), vec.end()}, X{});  // find X{} in vec

注意

C++ 代码中,范围的使用很普遍。一般都是隐式的,很难确保正确使用。尤其是, (p, n) 表示一个数组 [p:p+n) ,很难理清楚是要访问 *p 后面有 n 个元素。 span<T>span_p<T> 表示一个范围 [p:q) ,以 p 开始,以预测条件为真结束。

例子

void f(span<int> s)
{
    // range traversal (guaranteed correct)
    for (int x : s) cout << x << ' ';
    cout << endl;
    // C-style traversal (potentially checked)
    for (gsl::index i = 0; i < s.size(); ++i) cout << s[i] << ' ';
    cout << endl;
    // random access (potentially checked)
    s[2] = 9;
    //s[7] = 10; // terminate called without an active exception

    // extract pointers (potentially checked)
    std::sort(&s[0], &s[s.size() / 2]);
    for (int x : s) cout << x << ' ';
}
int main()
{
    int ss[] = {4, 3, 2, 1, 2, 3};
    f(ss);
    return 0;
}
4 3 2 1 2 3
4 3 2 1 2 3
3 4 9 1 2 3

注意

span<T> 并不保留其元素值,非常轻量,所以可以以值传递。

传递 span 对象的效率跟传递两个指针对,或指针+数量一样。

强化

  • (复杂)警告:访问指针参数的时候,其范围又由另外参数指定。建议使用 span