前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++核心准则编译边学-F.43 永远不要返回指向局部对象的指针或引用

C++核心准则编译边学-F.43 永远不要返回指向局部对象的指针或引用

作者头像
面向对象思考
发布2020-03-25 15:27:40
6850
发布2020-03-25 15:27:40
举报

F.43: Never (directly or indirectly) return a pointer or a reference to a local object

无论直接还是间接,永远不要返回指向局部对象的指针或引用。

Reason(原因)

To avoid the crashes and data corruption that can result from the use of such a dangling pointer.

为了避免使用这个悬空指针而引起崩溃和数据破坏。

Example, bad(反面示例)

After the return from a function its local objects no longer exist:

当程序从函数退出之后,函数中的局部变量就不再存在了。

代码语言:javascript
复制
int* f()
{
    int fx = 9;
    return &fx;  // BAD
}

void g(int* p)   // looks innocent enough
{
    int gx;
    cout << "*p == " << *p << '\n';
    *p = 999;
    cout << "gx == " << gx << '\n';
}

void h()
{
    int* p = f();
    int z = *p;  // read from abandoned stack frame (bad)
    g(p);        // pass pointer to abandoned stack frame to function (bad)
}

Here on one popular implementation I got the output:

这是一段很一般代码,我得到了以下输出:

代码语言:javascript
复制
*p == 999
gx == 999

I expected that because the call of g() reuses the stack space abandoned by the call of f() so *p refers to the space now occupied by gx.

我预期如此是因为对g()的调用再次使用了调用f()之后放弃的堆栈空间,因此*p访问的是现在被gx占用的空间。

  • Imagine what would happen if fx and gx were of different types. 想象一下如果fx和gx是不同类型时会发生什么。 译者注:变量会被修改为完全无关的值。
  • Imagine what would happen if fx or gx was a type with an invariant. 想象一下如果fx和gx是一种包含不变式的类型时会发生什么。 译者注:不变式会被莫名其妙地破坏。
  • Imagine what would happen if more that dangling pointer was passed around among a larger set of functions. 进一步想象一下如果悬空指针在更多函数之间传递是会发生什么。 译者注:会有跟多的函数和局部变量受到影响。
  • Imagine what a cracker could do with that dangling pointer. 想象一下破密者会如果处理悬空指针。 译者注:破密者可以通过这个人变量改变函数的行为。

Fortunately, most (all?) modern compilers catch and warn against this simple case.

幸运的是,大部分(所有?)现代编译器都可以捕捉并对这个简单的情况报警。

Note(注意)

This applies to references as well:

这一问题也适用于引用的情况。

代码语言:javascript
复制
int& f()
{
    int x = 7;
    // ...
    return x;  // Bad: returns reference to object that is about to be destroyed
}
Note(注意)

This applies only to non-static local variables. All static variables are (as their name indicates) statically allocated, so that pointers to them cannot dangle.

这个问题只适用于非静态全局变量。所有的静态变量(就像名称所表示的)都是静态分配内存,因此指向它们的指针不会悬空。

Example, bad(反面示例)

Not all examples of leaking a pointer to a local variable are that obvious:

不是所有泄漏指向局部变量指针的示例都是明显的。

代码语言:javascript
复制
int* glob;       // global variables are bad in so many ways

template<class T>
void steal(T x)
{
    glob = x();  // BAD
}

void f()
{
    int i = 99;
    steal([&] { return &i; });
}

int main()
{
    f();
    cout << *glob << '\n';
}

Here I managed to read the location abandoned by the call of f. The pointer stored in glob could be used much later and cause trouble in unpredictable ways.

这段代码中我设法读取函数f被调用后放弃的局部变量。保存在glob中的指针可以在很长时间之后被使用并以无法预期的方式带来麻烦。

Note(注意)

The address of a local variable can be "returned"/leaked by a return statement, by a T& out-parameter, as a member of a returned object, as an element of a returned array, and more.

局部变量的地址以多种方式被“返回”或者说被泄漏。具体的方式可以是通过返回语句,T&类型的输出参数,返回值对象的成员,返回值数组的元素或者是其它方式。

Note(注意)

Similar examples can be constructed "leaking" a pointer from an inner scope to an outer one; such examples are handled equivalently to leaks of pointers out of a function.

类似地,也可以构造出从内部作用域向外部作用域“泄漏”指针的例子。这样的例子等价于向函数外部泄漏(指向局部变量的)指针。

A slightly different variant of the problem is placing pointers in a container that outlives the objects pointed to.

这个问题的稍微不同的版本是将指针放到生命周期超过指针所指向对象的容器中的情况。

See also: Another way of getting dangling pointers is pointer invalidation. It can be detected/prevented with similar techniques.

参见:产生悬空指针的另一种情况是指针无效化。它可以通过类似的技术检查或防止。

译者注:指针无效化应该是指针本来指向的是一个有效对象,但后来对象被销毁而指针没有被同时清空的情况。

Enforcement(实施建议)
  • Compilers tend to catch return of reference to locals and could in many cases catch return of pointers to locals. 编译器倾向于捕捉返回指向局部变量的引用的情况,也可以在很多情况下捕捉返回指向局部变量的指针的情况。
  • Static analysis can catch many common patterns of the use of pointers indicating positions (thus eliminating dangling pointers) 静态分析可以发现许多使用指针表示位置的通常形式,这样就可以排除悬空指针。

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

关注【面向对象思考】,轻松学习每一天!

有任何疑问,欢迎留言提问或讨论。


面向对象设计,面向对象编程,面向对象思考!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 面向对象思考 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • F.43: Never (directly or indirectly) return a pointer or a reference to a local object
    • Reason(原因)
      • Example, bad(反面示例)
        • Note(注意)
          • Note(注意)
            • Example, bad(反面示例)
              • Note(注意)
                • Note(注意)
                  • Enforcement(实施建议)
                  相关产品与服务
                  容器服务
                  腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档