2013-03-09 49 views
6

C++標準拋出異常狀態有關的std::call_once執行與拋出異常(§30.4.4.2/ 2)的功能如下:從標準:: call_once的

2 /效果:call_once的的執行那不稱它的功能是被動執行。調用其func的call_once的執行是主動執行。主動執行應調用INVOKE(DECAY_- COPY(std :: forward(func)),DECAY_COPY(std :: forward(args))...)。 如果這樣的func調用引發異常,則執行異常,否則返回。異常執行應將異常傳播給call_once的調用者。在任何給定once_flag的call_once的所有執行中:最多一個應該是返回執行;如果有一個返回的執行,它應該是最後一次執行;只有在執行完成後纔會被動執行。 [注意:被動執行允許其他線程可靠地觀察先前返回執行產生的結果。 - 注完]

我使用Visual Studio 2012,並運行下面的代碼:

void f(){ 
    throw std::exception("Catch me!"); 
} 

int main(int argc, char* argv[]){ 
    once_flag flag; 
    try{ 
     call_once(flag, f); 
    } catch(const std::exception& e){ 
     cout << e.what() << endl; 
    } 
    return 0; 
} 

我的結果是:在catch塊中運行的代碼,並打印消息,但是當程序存在我得到abort()呼叫並打印以下信息來清點:

... \ mutex.c(38)互斥破壞而忙碌

這是否應該發生?

+2

不,這是一個錯誤,程序應該可以正常工作(儘管你對'std :: exception'使用非標準的構造函數,在ISO C++中,你只能默認構造'std :: exception',頻繁的可移植性問題,當MSVC用戶檢查incode是要在其他實現編譯) – 2013-03-09 14:14:49

回答

7

這是應該發生的嗎?

不,不是真的。這是一個錯誤

但是,請注意一個事實,即VC11並不孤單在這:

  • 英特爾ICC 13.0.1調用std::terminate()好像你的異常沒有被處理(見live example);
  • GCC 4.8.0 beta可能做類似的事情,但它不顯示任何輸出,它只是吞下異常並以靜默終止程序(請參閱live example)。 [UPDATE:此錯誤似乎並沒有在其他enviroments重複性好,很可能是與liveworkspace.org僅配置的問題]

GCC 4.7.2和3.2鏘,在另一方面,表現正確。

順便說一句,值得注意的是C++標準(第18.8.1節)指定了std::exceptiononly has a default constructor and a copy constructor。您正在使用的構造函數最可能是不可移植的MS擴展。

您可以考慮使用std::logic_error相反,從std::exception派生並支持構造函數接受一個字符串。

+1

謝謝,我不知道std :: exception只有一個默認和複製構造函數,我實際上在原始代碼中使用自定義異常。現在我不會拋出call_once的異常,謝謝澄清。 – 2013-03-09 15:18:49

+4

值得注意的是,當'call_once'返回一個異常時,它不被視爲滿足。即下次執行'call_once'時,將再次嘗試'f'。依此類推,直到'f'返回而沒有拋出異常。 – 2013-03-09 16:05:09

+0

@HowardHinnant:很好的觀察,謝謝你提到。 – 2013-03-09 16:06:29