參看維基百科:
===============================================================================================
溫馨提示:由於本人英語水品有限,有些地方翻譯得可能不準確,也比較生澀。
===============================================================================================
當所指向的對象被釋放或者收回,但是對該指針沒有作任何的修改,以至於該指針仍舊指向已經回收的內存地址,此情況下該指針便稱懸垂指針(也叫迷途指針)。
某些編程語言允許未初始化的指針的存在,而這類指針即爲野指針。
懸垂指針的成因:
在許多編程語言中(比如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 # }
調用 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/submarine/
*************************************************************************/