2010-07-15 45 views
7

我碰到下面的代碼近日傳出:合法/定義明確的C++調用不通過空指針訪問成員的非靜態方法嗎?

class Foo 
{ 
public: 
    void bar(); 
    // .. other stuff 
}; 

void Foo::bar() 
{ 
    if(!this) { 
     // .. do some stuff without accessing any data members 
     return; 
    } 

    // .. do normal actions using data members 
} 

代碼編譯,因爲在C++方法只是被隱式傳遞一個指針「這個」和「這個」可以被檢查爲NULL,就像任何功能其他指針。很明顯,這段代碼雖然沒有崩潰,但是它很混亂,而且很糟糕。在調試器中遍歷代碼會非常困難,看到一個NULL指針即將調用一個方法,然後看不到預期的崩潰。我的問題是:是否違反C++標準調用SomeFooPtr->bar()其中SomeFooPtr == NULL

它發生在我身上,它可能不會因爲用戶定義的操作符 - >返回一個指針,這意味着即使該指針爲NULL,它肯定沒有被解除引用(取消引用一個NULL指針,我相信是被視爲由標準規定爲非法或未定義)。另一方面,原始指針的語義不一定必須與用戶定義的指針的語義相匹配 - 即使編譯器不會生成一個指針,操作符也可能被視爲解引用。

+0

Duplicate:http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-behav – GManNickG 2010-07-15 17:23:30

回答

13

這可能適用於大多數系統,但它是未定義的行爲。答曰標準:

5.2.5.3

如果E1具有類型「指針類X」,則表達E1->E2被轉換爲等效的形式(*(E1)).E2 [...]

和:

5.2.5.1

後綴表達式後跟一個點.或箭頭->,後面可能跟着關鍵字template(14.8.1),然後是id-表達式,是一個後綴表達式。評估點或箭頭之前的後綴表達式; 58) [...]

58)該評估發生即使結果是不必要的,以確定整個後綴表達式的值,例如,如果與ID-表達式表示靜態成員。

*x評價,其中x是不確定的行爲一個空指針的結果,所以你顯然是UB的情況下,即使進入該功能前。

+0

謝謝,這正是我在找什麼。 – 2010-07-15 16:27:31

+0

對不起,編輯混亂。首先我忽略了標準中的某些內容,然後我誤解了你的問題。現在應該可以。 – Thomas 2010-07-15 16:28:32

+0

您能給出一個「A.template B」形式表達式的例子嗎?這個語法在哪裏相關? – Philipp 2010-07-15 16:47:32

1

如果它是合法的,它會讓讀者感到困惑。在代碼工作的實現中,vtable按類型訪問,當然不是按對象訪問。另外,我希望這段代碼能夠掩蓋構造函數的失敗,這會掩蓋其他地方的各種問題。應該正確處理構造函數失敗,而不是像例子那樣使用討厭的kludge。

1

這是(現在都在一起)未定義的行爲。但是,對於許多編譯器來說,它將起作用,並且還有額外的限制,即該方法必須是非虛擬的。

1

這是UB。使其崩潰的一個好方法是將其用作使用多重繼承的派生類的基類。因人而異。

7

即使取消引用不是UB,該測試也會中斷。當這種多重遺傳調整進入遊戲時,它會中斷:

#include <stdio.h> 
class B 
{ 
    int value; 
    public: 
    void foo() 
    { 
     if (!this) 
      printf("this==0\n"); 
     else 
      printf("safe\n"); 
    } 
}; 
class A { public: int anotherValue; }; 
class Z : public A,public B {}; 

int main() 
{ 
    Z *z=0; 
    z->foo(); 
} 

在此打印「安全」。

+0

極好的例子!謝謝。 – Vlad 2012-06-06 13:25:51

相關問題