2011-09-27 123 views
0

請檢查此代碼..C++奇怪的行爲

class ex 
{ 
    int i; 
    public: 
    ex(int ii = 0):i(ii){} 
     ~ex(){cout<<"dest"<<endl;} 
    void show() 
    { 
     cout<<"show fun called"<<endl; 
    } 
}; 
int main(int argc , char *argv[]) 
{ 
    ex *ob = NULL; 
    ob->show(); 
     return 0; 
} 

當我們調用show方法會發生什麼。

謝謝..

+2

這個問題的真正答案是沒有人能夠回答**究竟會發生什麼**。 – Mahesh

+0

@Mahesh技術上說它會導致未定義的行爲是答案。我們不知道這種未定義的行爲是什麼並不重要。換句話說,「未定義的行爲」正是會發生的事情。 – sashang

+0

許多問題的另一個問題是[karthik](http://stackoverflow.com/users/644073/karthik)或[user692270](http://stackoverflow.com/users/692270/user692270)接受@karthik的答案。嚴重的是,你是否患有自卑感? –

回答

3
ex *ob = NULL; 
ob->show(); 

你提領一空指針導致不確定的行爲。這不好。

如果不清楚解除引用的位置,則理解->運算符轉換爲 (*ob).show()

+0

大聲笑,這得到了一個downvote - 小丑必須今天有效。 – sashang

+0

我沒有downvote,但你的答案是不正確的。 show()函數可以是靜態的:它不使用隱式的指針,所以沒有什麼不好的事情會發生。只有當函數試圖訪問成員變量時,調用對象的虛擬成員函數等,空指針纔會被解除引用。 – TonJ

+0

@TonJ:'show()'不是靜態的,可以在類定義中看到。 – DevSolar

0

行爲未定義。程序的實際行爲如何依賴於實現。我期望大多數實現嘗試執行代碼而不檢查指針。所以你的第一個例子應該運行平穩,因爲它沒有引用該類的任何本地成員。

有趣的是,檢查下面的代碼做什麼:

class ex 
{ 
    int i; 
    public: 
    ex(int ii = 0):i(ii){} 
    ~ex(){cout<<"dest"<<endl;} 
    virtual void show() 
    { 
     cout<<"show fun called"<<endl; 
    } 
}; 

int main(int argc , char *argv[]) 
{ 
    ex *ob = NULL; 
    ob->show(); 
    return 0; 
} 

如果該方法是虛擬的,也許在運行時需要訪問對象的某些本地數據,導致空指針或錯誤的地址例外。

EDIT

我用GCC測試上的cygwin以下略作修改示例:

#include <iostream> 

using namespace std; 

class ex 
{ 
    int i; 
    public: 
    ex(int ii = 0):i(ii){} 
    ~ex(){cout<<"dest"<<endl;} 

    void show() 
    { 
     cout<<"show fun called"<<endl; 
    } 

    virtual void vshow() 
    { 
     cout<<"vshow fun called"<<endl; 
    } 
}; 

int main(int argc , char *argv[]) 
{ 
    ex *ob = NULL; 
    ob->show(); 
    ob->vshow(); 
    return 0; 
} 

,事實上,輸出爲:

show fun called 
Segmentation fault (Core dumped) 
+0

有沒有這樣的事情,作爲空指針異常在C++ – sashang

+0

我並不是說C++運行時本身拋出異常,當您嘗試解除引用NULL指針時,它由操作系統拋出。結果是程序崩潰。 – Giorgio

+0

當您引用無效內存時,操作系統執行的操作與操作系統有關。在linux上,生成一個SIGSEGV信號(http://en.wikipedia.org/wiki/SIGSEGV)併發送給程序,而不是空指針異常。你答案的原始措詞是誤導性的。 – sashang

1

調用show方法對由空指針指向的對象進行分類爲「未定義行爲」,這意味着無論發生什麼事情不能說C++是錯誤的,因爲錯誤在你身邊。

未定義的行爲意味着編譯器編寫者不需要關心錯誤編程的後果......所以他們可以自由地忽略這些情況。通常未定義的行爲被認爲意味着「崩潰」,但這與事實相去甚遠。執行代碼未定義行爲可能崩潰,可以什麼都不做,可以顯然什麼也不做,讓你的程序崩潰以後在完美的罰款代替一個百萬條指令或者它甚至可以在所有,但靜默運行顯然很好,沒有崩潰破壞您的數據。

C++語言的一個主要假設是程序員沒有犯錯。在其他語言中,這不是真的,你會得到「運行時錯誤天使」,當你犯了一個錯誤時,它會檢查和停止你的程序...在C++中,而不是那些檢查被認爲是太昂貴,因此,而不是「運行時錯誤天使」 「未定義的行爲守護進程」,如果出現錯誤,您將獲得樂趣。我認爲C++對初學者來說是一個非常不好的選擇(初學者犯了很多錯誤),並且通過實驗學習C++是不可能的(因爲C++的後果)錯誤是非確定性的)。

在您的具體情況下,考慮到編譯器編寫者懶惰(對於程序員來說質量並不差),我猜測在x86架構上代碼不會造成任何損害,並且可能會像指針一樣執行對一個有效的對象。 這當然只是推測,因爲它取決於編譯器,硬件和編譯器選項。可能有好的編譯器有一個編譯調試選項,它會生成崩潰的代碼。

3

這是未定義的行爲。

話雖這麼說,在大多數編譯器,你就可以,只要來調用空指針作爲方法

1)他們不訪問成員。

2)它們不是虛擬的。

大多數編譯器將轉化

ob->show() 

call ob::show 

,其存在於該應用程序空間內的有效方法。由於您沒有訪問會員,所以沒有理由導致崩潰。

+0

應該提到「能夠在大多數編譯器上執行此操作」並不會改變它仍然是未定義行爲的事實,即代碼中的錯誤。 – DevSolar

+0

這是我的第一句話...... –

+1

......但其他人給人的印象是,這樣做是有點好的,而且「沒有理由讓人崩潰」,這是恕我直言,這裏給出的錯誤信息。這是不確定的行爲,不要這樣做,期限。 – DevSolar