• 悬垂指针(Dangling pointer)和野指针(Wild pointer)


    参看维基百科:

    Dangling pointer

    迷途指针

    ===============================================================================================

    温馨提示:由于本人英语水品有限,有些地方翻译得可能不准确,也比较生涩。

    ===============================================================================================

    当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称悬垂指针(也叫迷途指针)。

    某些编程语言允许未初始化的指针的存在,而这类指针即为野指针

    悬垂指针的成因:

    在许多编程语言中(比如C),显示地从内存中删除一个对象或者返回时通过销毁栈帧,并不会改变相关的指针的值。该指针仍旧指向内存中相同的位置,即使引用已经被删除,现在可能已经挪作他用。

    一个简单的例子:

    {
       char *dp = NULL;
       /* ... */
       {
           char c;
           dp = &c;
       } /* c falls out of scope */
         /* dp is now a dangling pointer */
    }

    如果操作系统能够侦测运行时的指向空指针的引用,一个方案是在内部快消失之前给dp赋为0(NULL)。另一个方案是保证dp在没有被初始化之前不再被使用。

    另一个常见原因是混用 malloc() 和 free():当一个指针指向的内存被释放后就会变成悬垂指针。正如上个例子,可以避免这个问题的一种方法是在释放它的引用后把指针重置为NULL。

    #include <stdlib.h>
     
    void func()
    {
        char *dp = malloc(A_CONST);
        /* ... */
        free(dp);         /* dp now becomes a dangling pointer */
        dp = NULL;        /* dp is no longer dangling */
        /* ... */
    }

    一个很常见的失误是返回一个栈分配的局部变量:一旦调用的函数返回了,分配给这些变量的空间被回收,此时它们拥有的是“垃圾值”。

    int *func(void)
    {
        int num = 1234;
        /* ... */
        return &num;
    }

    调用 func 后,尝试从该指针暂时能读取到正确的值(1234),但是再次调用函数后将会重写栈为 num 分配的的值,再从该指针读取的值就不正确了。如果必须要返回一个指向 num 的指针,num 的作用域必须大于这个函数——它也许被声明为 static。

    野指针的成因:

    野指针的产生是由于在首次使用之前没有进行必要的初始化。因此,严格地说,在编程语言中的所有为初始化的指针都是野指针。

    int f(int i)
    {
        char *dp;    /* dp is a wild pointer */
        static char *scp;  /* scp is not a wild pointer:
                            * static variables are initialized to 0
                            * at start and retain their values from
                            * the last call afterwards.
                            * Using this feature may be considered bad
                            * style if not commented */
    }

     dp 是一个野指针。scp 不是一个野指针:静态变量一开始被初始化为0,从最后一次调用后保持着它们的值。如果没有注释,使用这个特性也许被视为不良风格。

    避免悬垂指针错误:

    在 C/C++ 中,一种最简单的技术是实现一个 free()(或类似的)替代版本或者 delete 析构器来保证指针的重置。然后,这个技术不会清除其他指针变量,它们含有该指针的副本。

    /* Alternative version for 'free()' */
    void safefree(void **pp)
    {
        if (pp != NULL) {               /* safety check */
            free(*pp);                  /* deallocate chunk, note that free(NULL) is valid */
            *pp = NULL;                 /* reset original pointer */
        }
    }
     
    int f(int i)
    {
        char *p = NULL, *p2;
        p = (char *)malloc(1000);    /* get a chunk */
        p2 = p;              /* copy the pointer */
        /* use the chunk here */
        safefree(&p);       /* safety freeing; does not affect p2 variable */
        safefree(&p);       /* this second call won't fail */
        char c = *p2;       /* p2 is still a dangling pointer, so this is undefined behavior. */
    }

    替换版本可以用来保证在调用 malloc() 之前一个空指针的正确性:

    safefree(&p);        /* i'm not sure if chunk has been released */
    p = malloc(1000);    /* allocate now */

    这些用法可以通过 #define 指令来构造有用的宏指令,创建像元语言的东西来掩饰或者被嵌入到一个工具库中。但凡使用这个技术的程序员在会用到 free()的地方应该使用安全版本;不这么做会再次导致这些问题。另外,这个解决方案局限于单个程序或工程的作用域中,并且应该正确地写入文档。

    在更多结构化的解决方案中,一种流行的避免悬垂指针的技术是使用智能指针。一个智能指针通常使用引用技术来收回对象。还有些技术包括 tombstones 方法和 locks-and-keys 方法。

    另一个方法是使用 Boehm 垃圾收集器,一种保守的垃圾收集器,取代C和C++中的标准内存分配函数。此法通过禁止内存释放函数来完全消除悬垂指针引发的错误,通过收集垃圾来回收对象。

    像Java语言,悬垂指针这样的错误是不会发生的,因为Java中没有明确地重新分配内存的机制。而且垃圾回收器只会在对象的引用数为0时重新分配内存。


    /**************************************************************************
                      原文来自博客园——Submarinex的博客: www.cnblogs.com/submarinex/               
      *************************************************************************/

  • 相关阅读:
    oracle字符集查看修改
    oracle查看所有表及字段
    oracle重新启动步骤
    oracle job 定时执行 存储过程
    oracle导入导出exp,imp
    oracle创建表空间
    Oracle Dataguard HA (主备,灾备)方案部署调试
    Moving Tables-贪心
    Windows下Android开发环境配置
    在单进程单线程或单进程多线程下实现log4cplus写日志并按大小切割
  • 原文地址:https://www.cnblogs.com/submarinex/p/2940169.html
Copyright © 2020-2023  润新知