专栏首页C++核心准则原文翻译C++核心准则ES.65:不要解引用无效指针

C++核心准则ES.65:不要解引用无效指针

ES.65: Don't dereference an invalid pointer

ES.65:不要解引用无效指针

Reason(原因)

Dereferencing an invalid pointer, such as nullptr, is undefined behavior, typically leading to immediate crashes, wrong results, or memory corruption.

解引用例如null等无效指针,是无定义的行为,通常会立即导致程序崩溃,错误的结果,或者内存破坏。

Note(注意)

This rule is an obvious and well-known language rule, but can be hard to follow. It takes good coding style, library support, and static analysis to eliminate violations without major overhead. This is a major part of the discussion of C++'s model for type- and resource-safety.

本规则显而易见而且众所周知,但却很难遵守。它会带来好的代码风格,更充分的库支持,不需要很大代价但可以排除违反的静态解析。这是关于C++类型和资源安全模型的论述的重要组成部分。

See also:(参见)

  • Use RAII to avoid lifetime problems.
  • 使用RAII避免生命周期问题。
  • Use unique_ptr to avoid lifetime problems.
  • 使用unique_ptr避免生命周期问题
  • Use shared_ptr to avoid lifetime problems.
  • 使用shared_ptr避免生命周期问题
  • Use references when nullptr isn't a possibility.
  • 如果不可能出现空指针,使用引用
  • Use not_null to catch unexpected nullptr early.
  • 使用not_null尽早捕获意外的空指针。
  • Use the bounds profile to avoid range errors.
  • 使用边界规则群组避免范围错误。

Example(示例)

void f()
{
    int x = 0;
    int* p = &x;

    if (condition()) {
        int y = 0;
        p = &y;
    } // invalidates p

    *p = 42;            // BAD, p might be invalid if the branch was taken
}

To resolve the problem, either extend the lifetime of the object the pointer is intended to refer to, or shorten the lifetime of the pointer (move the dereference to before the pointed-to object's lifetime ends).

为了解决这个问题,要么扩展对象指针意图指向的对象的生命周期,要么缩短指针的生命周期(将解引用操作移到所指向对象的生命周期结束之前。)

void f1()
{
    int x = 0;
    int* p = &x;

    int y = 0;
    if (condition()) {
        p = &y;
    }

    *p = 42;            // OK, p points to x or y and both are still in scope
}

Unfortunately, most invalid pointer problems are harder to spot and harder to fix.

不幸的是,大多数无效指针问题难于发现,也难于修改。

Example(示例)

void f(int* p)
{
    int x = *p; // BAD: how do we know that p is valid?
}

There is a huge amount of such code. Most works -- after lots of testing -- but in isolation it is impossible to tell whether p could be the nullptr. Consequently, this is also a major source of errors. There are many approaches to dealing with this potential problem:

这样的代码大量存在。在经历了大量测试之后,大部分情况下可以动作,但是如果只看局部很难判断一个指针有没有可能为空。因此,空指针也是错误的主要来源之一。存在很多方法可以处理这个潜在问题:

void f1(int* p) // deal with nullptr
{
    if (!p) {
        // deal with nullptr (allocate, return, throw, make p point to something, whatever
    }
    int x = *p;
}

There are two potential problems with testing for nullptr:

检查指针是否为空会有两个潜在问题:

  • it is not always obvious what to do what to do if we find nullptr
  • 在发现了空指针时应该做什么并不总是很明确。
  • the test can be redundant and/or relatively expensive
  • 检查可能是多余的而且/或者代价相当高。
  • it is not obvious if the test is to protect against a violation or part of the required logic.
  • 很难判断这个检查只是为了防止违反还是必要逻辑的一部分。
void f2(int* p) // state that p is not supposed to be nullptr
{
    assert(p);
    int x = *p;
}

This would carry a cost only when the assertion checking was enabled and would give a compiler/analyzer useful information. This would work even better if/when C++ gets direct support for contracts:

这种做法只在断言检查有效时需要付出一定的代价,同时可以为编译器/解析器提供有用信息。如果C++得到协议(contracts)的直接支持的话,效果会更好:

void f3(int* p) // state that p is not supposed to be nullptr
    [[expects: p]]
{
    int x = *p;
}

Alternatively, we could use gsl::not_null to ensure that p is not the nullptr.

另外,我们可以使用gsl::not_null来保证p不是空指针。

void f(not_null<int*> p)
{
    int x = *p;
}

These remedies take care of nullptr only. Remember that there are other ways of getting an invalid pointer.

这个改进只处理空指针。别忘了还有其他形式的无效指针。

Example(示例)

void f(int* p)  // old code, doesn't use owner
{
    delete p;
}

void g()        // old code: uses naked new
{
    auto q = new int{7};
    f(q);
    int x = *q; // BAD: dereferences invalid pointer
}
Example(示例)
void f()
{
    vector<int> v(10);
    int* p = &v[5];
    v.push_back(99); // could reallocate v's elements
    int x = *p; // BAD: dereferences potentially invalid pointer
}
Enforcement(实施建议)

This rule is part of the lifetime safety profile

本规则是生命周期规则群组的一部分

  • Flag a dereference of a pointer that points to an object that has gone out of scope
  • 如果指针指向的对象已经处于生命周期之外,标记它的解引用操作。
  • Flag a dereference of a pointer that may have been invalidated by assigning a nullptr
  • 如果指针由于被设为空指针而无效时,标记它的解引用操作。
  • Flag a dereference of a pointer that may have been invalidated by a delete
  • 如果由于指针指向的对象被销毁而无效时,标记它的解引用操作。
  • Flag a dereference to a pointer to a container element that may have been invalidated by dereference
  • 如果指针指向的容器元素由于解引用而无效时,标记它的解引用操作。

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es65-dont-dereference-an-invalid-pointer


觉得本文有帮助?请分享给更多人。

关注微信公众号【面向对象思考】轻松学习每一天!

面向对象开发,面向对象思考!

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

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

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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C++核心准则ES.20: 保证所有对象被初始化

    Avoid used-before-set errors and their associated undefined behavior. Avoid prob...

    面向对象思考
  • C++核心准则F.52:在lambda表达式中使用引用形式捕捉局部变量

    F.52 在lambda表达式中使用引用形式捕捉局部变量,包含向算法传递变量的情况。

    面向对象思考
  • C++核心准则R.3: 原始指针(T*)不应拥有所有权

    There is nothing (in the C++ standard or in most code) to say otherwise and most...

    面向对象思考
  • 春节停车难?用Python找空车位

    作者通过相机结合深度学习算法,基于 Python 语言建立一个高精度的停车位的通知系统,每当有新停车位时就会发短信提醒我。听起来好像很复杂,真的方便实用吗?但实...

    CDA数据分析师
  • [Hot Technology系列]从此之后再无Load Balancer--SmartStack

    什么是SmartStack? SmartStack is an automated service discovery and registration fr...

    包子面试培训
  • CodeForces Roads not only in Berland(并查集)

    H - Roads not only in Berland Time Limit:2000MS     Memory Limit:262144KB    ...

    ShenduCC
  • Qualcomm - SnapDragon Tech Summit - Key Note - About 5G

    Qualcomm SnapDragon Tech Summit首日Keynote。 Qualcomm对5G现状和未来的理解,及其技术框架。非常重要。

    用户6026865
  • tf.contrib.layers.batch_norm

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    于小勇
  • Mutex VS. Semaphore

    The key point is that mutexes should be used to protect shared resources, while ...

    lesM10
  • WEE &SEE角色设定

    腾讯ISUX

扫码关注云+社区

领取腾讯云代金券