专栏首页C++核心准则原文翻译C++核心准则ES.42: 使用指针时要简单且直接

C++核心准则ES.42: 使用指针时要简单且直接

ES.42: Keep use of pointers simple and straightforward

ES.42: 使用指针时要简单且直接

Reason(原因)

Complicated pointer manipulation is a major source of errors.

复杂的指针操作是错误的主要来源之一。

Note(注意)

Use gsl::span instead. Pointers should only refer to single objects. Pointer arithmetic is fragile and easy to get wrong, the source of many, many bad bugs and security violations.span is a bounds-checked, safe type for accessing arrays of data. Access into an array with known bounds using a constant as a subscript can be validated by the compiler.

使用gls::span。指针只应该用于参照单独的对象。指针运算脆弱且易错,会导致特别特别多的错误和安全违反。span类型提供了具有边界检查的、安全的访问数组数据的手段。使用常数下标访问一个已知边界的数组的操作可以在编译时检查。

Example, bad(反面示例)
void f(int* p, int count)
{
    if (count < 2) return;

    int* q = p + 1;    // BAD

    ptrdiff_t d;
    int n;
    d = (p - &n);      // OK
    d = (q - p);       // OK

    int n = *p++;      // BAD

    if (count < 6) return;

    p[4] = 1;          // BAD

    p[count - 1] = 2;  // BAD

    use(&p[0], 3);     // BAD
}

Example, good(范例)

void f(span<int> a) // BETTER: use span in the function declaration
{
    if (a.size() < 2) return;

    int n = a[0];      // OK

    span<int> q = a.subspan(1); // OK

    if (a.size() < 6) return;

    a[4] = 1;          // OK

    a[a.size() - 1] = 2;  // OK

    use(a.data(), 3);  // OK
}

Note(注意)

Subscripting with a variable is difficult for both tools and humans to validate as safe.span is a run-time bounds-checked, safe type for accessing arrays of data.at() is another alternative that ensures single accesses are bounds-checked. If iterators are needed to access an array, use the iterators from a span constructed over the array.

使用变量下标的情况下确保安全性无论对工具还是人都很困难。span是访问数组数据的安全类型,可以提供执行时的范围检查。at()是确保单独访问时进行边界检查的另一种方式。如果迭代器需要访问数组,使用来自构建在数组之上的span的迭代器。

Example, bad(反面示例)
void f(array<int, 10> a, int pos)
{
    a[pos / 2] = 1; // BAD
    a[pos - 1] = 2; // BAD
    a[-1] = 3;    // BAD (but easily caught by tools) -- no replacement, just don't do this
    a[10] = 4;    // BAD (but easily caught by tools) -- no replacement, just don't do this
}

Example, good(范例)

Use a span:

使用span:

void f1(span<int, 10> a, int pos) // A1: Change parameter type to use span
{
    a[pos / 2] = 1; // OK
    a[pos - 1] = 2; // OK
}

void f2(array<int, 10> arr, int pos) // A2: Add local span and use that
{
    span<int> a = {arr.data(), pos};
    a[pos / 2] = 1; // OK
    a[pos - 1] = 2; // OK
}

Use at():

使用at():

void f3(array<int, 10> a, int pos) // ALTERNATIVE B: Use at() for access
{
    at(a, pos / 2) = 1; // OK
    at(a, pos - 1) = 2; // OK
}

Example, bad(反面示例)

void f()
{
    int arr[COUNT];
    for (int i = 0; i < COUNT; ++i)
        arr[i] = i; // BAD, cannot use non-constant indexer
}

Example, good(范例)

Use a span:

使用span:

void f1()
{
    int arr[COUNT];
    span<int> av = arr;
    for (int i = 0; i < COUNT; ++i)
        av[i] = i;
}

Use a span and range-for:

使用span和范围for:

void f1a()
{
     int arr[COUNT];
     span<int, COUNT> av = arr;
     int i = 0;
     for (auto& e : av)
         e = i++;
}

Use at() for access:

使用at()访问:

void f2()
{
    int arr[COUNT];
    for (int i = 0; i < COUNT; ++i)
        at(arr, i) = i;
}

Use a range-for:

使用范围for:

void f3()
{
    int arr[COUNT];
    int i = 0;
    for (auto& e : arr)
         e = i++;
}

Note(注意)

Tooling can offer rewrites of array accesses that involve dynamic index expressions to use at() instead:

工具可以建议重写包含动态索引运算的数组访问代码,转而使用at()。

static int a[10];

void f(int i, int j)
{
    a[i + j] = 12;      // BAD, could be rewritten as ...
    at(a, i + j) = 12;  // OK -- bounds-checked
}

Example(示例)

Turning an array into a pointer (as the language does essentially always) removes opportunities for checking, so avoid it。

将数组转换为指针(像语言一直在做的那样)放弃了检查的机会,应该避免。

void g(int* p);

void f()
{
    int a[5];
    g(a);        // BAD: are we trying to pass an array?
    g(&a[0]);    // OK: passing one object
}

If you want to pass an array, say so:

如果想传递一个数组,这样做:

void g(int* p, size_t length);  // old (dangerous) code

void g1(span<int> av); // BETTER: get g() changed.

void f2()
{
    int a[5];
    span<int> av = a;

    g(av.data(), av.size());   // OK, if you have no choice
    g1(a);                     // OK -- no decay here, instead use implicit span ctor
}

Enforcement(实施建议)

  • Flag any arithmetic operation on an expression of pointer type that results in a value of pointer type.
  • 标记对指针表达式进行数学运算然后得到指针类型的结果的情况。
  • Flag any indexing expression on an expression or variable of array type (either static array or std::array) where the indexer is not a compile-time constant expression with a value between 0 and the upper bound of the array.
  • 如果一个索引不是编译时可确定其值区间为0到数组上限的常量表达式,对数组类型变量或表达式的索引表达式的风险进行提示。
  • Flag any expression that would rely on implicit conversion of an array type to a pointer type.
  • 提示表达式依靠从数组到指针的隐式类型转换,提示。

This rule is part of the bounds-safety profile.

本规则是边界安全规则群组的一部分。

链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es42-keep-use-of-pointers-simple-and-straightforward

本文分享自微信公众号 - 面向对象思考(OOThinkingDalian),作者:面向对象思考

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C++核心准则Per.19:以可以预测的方式访问内存

    Performance is very sensitive to cache performance and cache algorithms favor si...

    面向对象思考
  • C++核心准则ES.101:使用无符号类型进行位操作

    ES.101: Use unsigned types for bit manipulation

    面向对象思考
  • C++核心准则​ES.71: 如果可以,使用范围for代替普通的for语句

    Readability. Error prevention. Efficiency.

    面向对象思考
  • OpenMP对于嵌套循环应该添加多少个parallel for

         一个原则是:应该尽量少的使用parallelfor, 因为parallel for也需要时间开销。即:

    Dabelv
  • 【leetcode刷题】T40-根据字符出现频率排序

    Given a string, sort it in decreasing order based on the frequency of characters...

    木又AI帮
  • 洛谷P4007 小 Y 和恐怖的奴隶主(期望dp 矩阵乘法)

    首先不难想到一种暴力dp,设\(f[i][a][b][c]\)表示还有\(i\)轮没打,场上有\(a\)个1血,\(b\)个2血,\(c\)个三血

    attack
  • Codeforces Round #514 (Div. 2) B. Forgery(思维+暴力)

    题目链接:http://codeforces.com/contest/1059/problem/B

    Ch_Zaqdt
  • 【PAT甲级】1002 A+B for Polynomials (25分)

    This time, you are supposed to find A+B where A and B are two polynomials.

    韩旭051
  • BZOJ3527: [Zjoi2014]力(FFT)

    那么\(E_j = \sum_{i = 1}^{j - 1} q_i (i - j)^2 - \sum_{i = j + 1}^n q_i (i - j)^2\...

    attack
  • 【HDU 4305】Lightning(生成树计数)

    There are N robots standing on the ground (Don't know why. Don't know how). 

    饶文津

扫码关注云+社区

领取腾讯云代金券