2014-03-07 123 views
2

我想知道爲什麼下面的小程序不會導致NullPointerException。 任何想法? 輸出是2x Hello World !!!在我的MacBook上使用clang-500.2.79。空指針可訪問

#include <iostream> 

using namespace std; 

class Strange { 
public: 
    Strange() {} 
    virtual ~Strange() {} 
    void sayHello() { 
     cout<<endl<<"Hello World!!!"<<endl; 
    } 

}; 

int main(void) { 
    Strange* s = new Strange(); 
    delete s; s = NULL; 
    s->sayHello(); 
    (*s).sayHello(); 
    return 0; 
} 

回答

2

我想知道爲什麼下面的小程序不會導致NullPointerException。

因爲它是C++,而不是一種「託管」語言,每次操作都需要昂貴的運行時檢查。如果您取消引用空指針,則不會發生異常;你會得到某種未定義的行爲。

在這種情況下,成員函數不訪問對象,因此(在大多數實現中)它的行爲就像指針是有效的一樣。如果它確實訪問了該對象,那麼您可能會遇到運行時錯誤或內存損壞,從而導致微妙的錯誤和不眠之夜。

避免指針和new當你可以;必要時使用智能指針和其他RAII技術。如果指針可能爲空,那麼在解引用它之前檢查它。

+0

不完全正確......我期望對NULL解引用有一個分段錯誤。不過,我認爲編譯器優化只是忽略瞭解引用操作,因爲該函數不使用'this'參數,所以不會發生實際的解除引用。 – immortal

+0

@immortal:只有當內存被訪問時,並且只有當指針指向一個不可訪問的內存頁面時,並且只有當硬件支持內存保護時。分段故障是一個硬件級別的故障,它只是由實際訪問內存的嘗試觸發的;它對解引用等軟件級概念一無所知。 –

+0

我嘗試了幾個編譯器優化,現在也嘗試了最新的gcc(從-O0直到O3),輸出始終工作,我從來沒有得到任何seg故障或其他異常:( – Mats

8

C++沒有「NullPointerException」。解引用空指針就是Undefined Behavior,任何事情都可能發生。

在你的情況,sayHello()不訪問*this可言,所以它發生在工作「正常」(你的編譯器,優化設置,運行時間& HW)。但這並不能保證。未定義的行爲只是未定義的;該程序可能會崩潰或在網上訂購披薩。

+0

謝謝你的回答。所以在將指針設置爲NULL之後我有未定義的行爲。如果我不會將指針設置爲NULL,那麼我有一個懸掛指針,對吧?這也有一些不確定的行爲,可能會更糟......所以我怎樣才能避免這種不確定的行爲? – Mats

+0

@ user3392371將指針設置爲空不是UB。 *解引用*這樣的指針是UB(如引用一個單位化的或更多的懸空指針)。解決方案取決於你的情況:如果指針可以爲null,則在使用之前測試它:'if(s)s-> sayHello();'。如果指針非空是你的代碼的前提條件,那麼將它作爲一個相應的調用來記錄它(即確保指針真的不爲空)。在這種情況下,你也可以'assert()'它不是null,這會讓你在調試版本中進行錯誤檢查。 – Angew