2010-03-09 39 views
12

我想知道,沒有其它目的不是純粹的好奇心(因爲任何人都不應該這樣寫代碼!)關於RAII的行爲如何與使用轉到金屬網格(可愛的想法是不是) 。當我們結合RAII和GOTO時會發生什麼?

class Two 
{ 
public: 
    ~Two() 
    { 
     printf("2,"); 
    } 
}; 

class Ghost 
{ 
public: 
    ~Ghost() 
    { 
     printf(" BOO! "); 
    } 
}; 

void foo() 
{ 
    { 
     Two t; 
     printf("1,"); 
     goto JUMP; 
    } 
    Ghost g; 
JUMP: 
    printf("3"); 
} 

int main() 
{ 
     foo(); 
} 

當在Visual Studio 2005中運行下面的代碼時,我得到以下輸出。

1,2,3 BOO! 

但是我想象,猜測,希望'BOO!'實際上不會出現,因爲Ghost應該從未實例化過(恕我直言,因爲我不知道此代碼的實際預期行爲)。

這是怎麼回事?


我意識到,如果我實例化鬼的代碼不編譯一個明確的構造函數...

class Ghost 
{ 
public: 
    Ghost() 
    { 
     printf(" HAHAHA! "); 
    } 
    ~Ghost() 
    { 
     printf(" BOO! "); 
    } 
}; 

啊,神祕......

+1

我相信這種行爲是正確的。否則,如何在JUMP之後引用變量g? – leiz 2010-03-09 05:00:50

+2

http://xkcd.com/292/ – 2010-03-09 05:21:19

回答

23

有關標準會談這明確地 - 用一個例子; 6.7/3「聲明聲明」(我強調加入):

每次執行聲明語句時,自動存儲持續時間的變量都會被初始化。 從塊退出時,塊中聲明的具有自動存儲持續時間的變量將被銷燬。

可以將其轉換爲塊,但不能以繞過具有初始化的聲明的方式。從具有自動存儲持續時間的局部變量不在範圍內的點跳轉到其範圍內的點的程序是格式錯誤的,除非該變量具有POD類型,並且沒有使用初始化程序進行聲明。

[示例:

void f() 
{ 
    //... 
    goto lx; //ill-formed: jump into scope of a 
    //... 

ly: 
    X a = 1; 
    //... 

lx: 
    goto ly; //OK, jump implies destructor 
       //call for a, followed by construction 
       //again immediately following label ly 
} 

末端示例]

所以,在我看來,MSVC的行爲是不符合標準 - Ghost不是一個POD類型,所以編譯器應該發出當goto語句被編碼跳過它時出錯。

我嘗試過的一些其他編譯器(GCC和Digital Mars)發佈錯誤。 Comeau發出警告(但公平地說,我爲Comeau構建的腳本配置了高MSVC兼容性,因此它可能會故意追蹤微軟的主管)。

+1

感謝您找到標準中定義的位置!然而,我不知道如果形成不良意味着它應該或不應該編譯... – 2010-03-09 05:28:53

+0

「不良形成」意味着該程序不是「良構」。編譯器只需接受和「正確執行」格式良好的程序。也就是說,如果它「不合格」,那就是錯誤的。 – greyfade 2010-03-09 05:43:40

+0

@Robert:我在這裏添加了一些關於MSVC行爲的話,因爲我最初應該這樣做。 – 2010-03-09 09:20:30

0

轉到沒有放射性。由goto離開與離開異常毫無區別。通過goto進入應該是方便的,而不是語言的限制。不知道鬼是否構造是一個不這樣做的好理由。

在構造函數之前跳轉。如果您想在某個對象已經構建之後跳入,請將其放入新範圍或以其他方式自行解析其生命週期。

0

在這種情況下,我發現以下方法很有用。

void foo() 
{ 
    { 
     Two t; 
     printf("1,"); 
     goto JUMP; 
    } 

    { 
     Ghost g; 
     // operations that use g. 
    } 

// g is out of scope, so following JUMP is allowed. 
JUMP: 
    printf("3"); 
} 

將變量g的範圍限制在foo()函數中,會使跳轉合法。現在,我們不是從g未初始化的地方跳到g預期初始化的地方。

相關問題