2012-03-16 77 views
0

根據C++標準,這是完全可以接受的做到這一點:- 對空>操作對象

class P 
{ 
    void Method() {} 
}; 

... 

P* p = NULL; 
p->Method(); 

然而,這種輕微的變化:

class P 
{ 
    virtual void Method() {} 
}; 

... 

P* p = NULL; 
p->Method(); 

產生訪問衝突時編譯Visual Studio 2005.

據我所知,這是由微軟的編譯器實現中的一些怪癖造成的,而不是由於我完全無能爲力造成的,所以問題是:

1)這種行爲是否存在於更新版本的VS中?

2)有沒有,我不知道,防止這種訪問衝突的編譯器設置?

+3

標準中的哪個位置可以使用? – 2012-03-16 14:00:01

回答

11

根據C++標準,這是完全可以接受這樣做

不,它不是!
取消引用NULL指針是未定義的行爲按照C++標準。 [#1]

但是,如果你不訪問任何成員非虛成員函數裏面極有可能在每個實施工作,因爲非虛成員函數的this只需要derefernced訪問成員this,因爲沒有成員在函數內部被訪問因此結果。
但是,僅僅因爲可觀察的行爲是好的並不意味着該程序是格式良好的 正確。
它仍然不合格。
然而這是一個無效的程序。

第二個版本崩潰,因爲在訪問虛擬成員函數時,即使調用相應的成員函數,即使在該成員函數內沒有成員訪問,也需要解引用this指針。

一個好的讀:
What's the difference between how virtual and non-virtual member functions are called?


[#1]參考:

C++ 03標準:§1.9/ 4

Certa在本標準中描述的其他操作未定義(例如,取消引用null指針的效果)。 [注意:本國際標準對含有未定義行爲的程序行爲沒有要求。 ]

+0

「如果你不訪問函數內部的任何成員」*並且它不是虛擬*。換句話說,如果你不給編譯器任何理由檢查你所調用的指針,它可能不會注意到指針是NULL。 – ruakh 2012-03-16 13:56:05

+1

呵呵,畢竟這是我純粹的無能,很高興知道:) – obamator 2012-03-16 13:56:26

+0

該程序是格式良好的,因爲它符合語法規則,可診斷語義規則和一個定義規則。 (被描述爲導致未定義行爲的規則明確地被排除在_diagnosable規則集之外。) – 2012-03-16 14:50:25

3

正如AI所說...我甚至會解釋爲什麼:在許多C++實現中,this指針只是作爲方法的第一個「隱藏」參數傳遞。所以,你看到了什麼是

void Method() {} 

真的

void Method(P* this) {} 

但對於虛方法它更復雜。運行時需要訪問指針來查找「真實」類型的P *,以便能夠調用方法的「正確」虛擬實現。所以它就像

p->virtualTable->Method(p); 

所以總是使用p。

0

首先,任何人都不會編譯,因爲您已將Method定義爲私有。

假設您將Method設爲公共,您最終會遇到未定義的行爲。基於典型的實現,大多數編譯器將允許第一個「工作」(對於工作的相當鬆散的定義),而第二個將基本上總是失敗。

這是因爲非虛擬成員函數基本上是一個正常的函數,它接收一個額外的參數。在該函數內部,關鍵字this引用該額外參數,該參數是指向調用該函數的類實例的指針。如果您通過空指針調用成員函數,它通常意味着該函數this內部將是空指針。只要函數中沒有任何內容試圖取消引用this,那麼您看到任何明顯的副作用的機會都很大。

但是,虛擬函數基本上是一個通過指針調用的函數。在一個典型的實現中,任何具有一個或多個虛擬函數的類(無論是直接在該類中定義,還是從基類繼承)都將有一個虛擬表。該類的每個實例(即每個對象)將包含一個指向其類的vtable的指針。當您嘗試通過指針調用虛擬函數時,編譯器將生成以下代碼:

  1. 提領指針。
  2. 獲取虛函數表的指針從該對象的適當偏移
  3. 取消引用虛函數表指針來獲取類的虛函數表
  4. 着眼於V表相應的位置獲得一個函數指針調用
  5. 調用該函數

給定一個空指針,該進程的第一步是將要中斷。

我會注意到這個記錄,這實際上適用於全部 C++編譯器。 VC++在這方面遠非獨一無二。恰恰相反 - 雖然編譯器在理論上可以實現與此不同的虛擬函數(舉一個例子),但實際情況是,我所知道的每個編譯器對於您發佈的代碼類型基本上都是相同的。事實上,所有C++編譯器都會在給定相同代碼的情況下顯示類似的行爲 - 實現中的主要差異大多是理論上的可能性,而不是您在實踐中可能遇到的差異。