2011-12-06 104 views
15

一個鮮爲人知的,但幾乎從來沒有使用C++的功能被賦予一個聲明:功能嘗試捕捉語法和主

void foo(); 

一個可能的,法律上的定義可能是:

void foo() try { 
    throw 42; 
} 
catch(...) { 
} 

這裏whole function implementation wrapped is within a try/catch pair,這似乎與允許this相似。

這是合法的做int main()?例如:

int main() try { 
    throw 42; 
} 
catch(...) { 
} 

The rules for main,n3290§3.6.1談論的大多是應該採取什麼樣的參數和它返回什麼 - 他們似乎並不明確禁止這樣做,因爲他們與其他各種奇怪的東西呢(如聯繫)你可能會試圖嘗試。

這是合法的嗎?

+2

有趣的學術問題,雖然我不確定它有很多實際用途。 http://stackoverflow.com/a/620817/10077 –

+0

法律?技術上大多數編譯器都會支持它。定義良好?不是真的,因爲我當然無法想出任何理智的做法。 – AJG85

+0

@ AJG85 - 我的意思是在「既不是未定義的行爲也沒有實現定義的行爲」的意義上進行了定義,而不是在「經過良好測試的常見實現方式」方式 – Flexo

回答

7

該標準並沒有禁止在[basic.start.main]它的使用,並同時迫使所有的實現支持至少int main() {/*...*/ }int main(int argc, char* argv[]) {/*...*/},並不限制這兩個聲明(3.6.1,第2段)的實現。

從孤立的看來,它至少會出現它是合法的,儘管當然只涉及函數聲明而不是函數定義。

讀上,[except.handle],第13周的狀態如下:

例外中對象的析構函數拋出具有靜態存儲 持續時間或在名稱空間範圍對象的構造沒有被捕獲 main()上的function-try-block。 (15.3第13段)

它使放置在一個main()功能試塊,這強烈地暗示,這種結構是合法的,並已定義的行爲的具體提及。在信息中加入main()只是其名稱和返回類型中的特殊信息,並且實現可能不會重載它以改變任何行爲,但是它是一種非常強大的情況,它以正常方式運行,除非特別注意,例如上面的引用。換句話說,是的,這是合法的和明確的。

我在這個答案的第一個版本中提供的博客文章實際上很好地說明了上面的blockquote給出的規則,所以我會retain the link to it,即使它沒有直接討論OP中的問題題。

關於對OP的評論,您可以在函數嘗試塊和[except。句柄]有這樣的說法:

流失功能嘗試塊的結尾等於返回 沒有值;這會導致返回值 函數(6.6.3)中出現未定義的行爲。 (15.3第15段)

如果你在的main一抓到底塊的時候,你就不會流過函數的身體(這將是在這種情況下,試塊) ,所以main自動調用return 0;的規則不適用。你需要返回一些int(很可能是一個錯誤代碼),以防止未定義。

+1

沒有太多的信息(關於定義),'靜態'constatations非常簡單:「全局」對象在'main'被調用之前被初始化並且在它返回之後被破壞...所以顯然不在'try/catch'內塊。至於關於構造函數語法的評論,是的,它很奇怪,但是並沒有真正回答這個問題...... –

+0

我同意那個評估,並且已經注意到了;謝謝。我發現一個明確的引用'main()'有function-try-blocks,所以我認爲這篇文章無論如何都是無用的。我將進行編輯以澄清此問題。 – matthias

+0

15.3的引用非常有趣。(這可能是我的下一個問題,如果它是合法的)結合約翰內斯與之相關的DR似乎可以回答它。 – Flexo

0

我試過了,它會編譯,並按預期運行。一個奇特的表述,但我認爲它沒有違反任何規則。 爲了清楚(自己和將來的代碼mantainers),你也可以改換爲:

int main() 
{ 
    try { 
     throw 42; 
    } 
    catch(int /*...*/) { 
    } 
} 
+4

它也適用於我的編譯器。 「編譯和運行」的問題是我知道我的編譯器編譯並運行了很多沒有很好定義的東西。 – Flexo

+1

公平點,@awoodland。所以,如果有疑問,我會建議使用上面提到的公式,這似乎完全符合您的要求。儘管您的原始配方似乎沒有違反標準的任何規定。 – alexandreC