2014-09-25 15 views
0

你好民間的StackOverflow。有條件地處理成員變量初始化期間的異常

有沒有更好的方法處理成員變量的構造函數中的異常?我不得不與一個庫類進行交互,它可能會或可能不會在它的構造函數中拋出異常(不能提前檢查),我想避免在我的類中使用指針(如果發生崩潰,我希望全部即使我搞砸了,也可以正確調用析構函數)。我已經目前此實現結算(包括了一個實例的虛擬存根):

class class_I_have_no_control_over{ 
    public: 
    class_I_have_no_control_over(int someArgument) 
    { 
     if(someInternalConditionThatCantBeTestedExternally) 
      throw anException; 
    } 

    class_I_have_no_control_over() 
    { //Does not throw 
    } 
} 

class MyClass{ 
    private: 
    class_I_have_no_control_over memberVariable; 

    public: 
    MyClass() 
    { 
     try{ 
      class_I_have_no_control_over tempVariable(24); 
      memberVariable = std::move(tempVariable); 
     }catch(...) 
     { 
      class_I_have_no_control_over tempVariable(); 
      memberVariable = std::move(tempVariable); 
     } 
    } 
} 

我認爲第一種方法是嘗試捕獲的初始化列表:即

class MyClass{ 
    private: 
    OtherClassThatTrowsOnConstruct member; 

    MyClass() 
     try: 
     member() 
     {//Normal constructor 
     } 
     catch(...) 
     {//Can translate an exception but cant stop it. 
     } 

但只能用這種方法翻譯異常,而不是阻止它們(如果你不拋出異常,運行時將重新拋出原始異常)。

有人會說使用動態分配(即與新的和刪除關鍵字的指針),但由於這個庫處理進程之間的共享內存,我有點厭倦了在發生崩潰時動態內存內容會發生什麼在其中一個應用程序中(例如析構函數從不調用,另一個應用程序正在等待不再運行的應用程序永遠不會意識到它不再監聽)。

+0

移動操作表明'class_I_have_no_control_over'使用動態內存分配。然後什麼阻止你做同樣的事情。無論如何,你總是可以使用就地建造(放置新的),並使用合適的緩衝區。 – 2014-09-25 15:37:22

+0

實際上,你確定'catch'裏面的'class_I_have_no_control_over tempVariable();'總是會成功嗎? – 2014-09-25 15:39:23

+0

@πάνταῥεῖ:該構造函數中的「不拋出」的註釋。 – 2014-09-25 15:39:57

回答

0

第一個版本會有所簡化,不改變其行爲:

MyClass() try { 
    memberVariable = class_I_have_no_control_over(24); // move from temporary 
} catch (...) { 
    // no need to do anything; memberVariable is already default-constructed 

    // Unless the class is so evil that move-assignment might fail and leave 
    // the target in a messed-up state. In which case you probably want 
    memberVariable = class_I_have_no_control_over(); 
    // If that fails, you should probably give up and let the exception go. 
} 

除非你有進一步的限制(例如無法移動類),這是對付你的情況最好的方式。如果它不可移動,那麼動態分配可能是一個合理的選擇;使用智能指針,可能是std::unique_ptr,以確保它與MyClass對象一起銷燬。

#include <memory> 

class MyClass{ 
    private: 
    std::unique_ptr<unmovable_evil> memberVariable; 

    public: 
    MyClass() try { 
     memberVariable.reset(new unmovable_evil(24)); 
    } catch(...) { 
     memberVariable.reset(new unmovable_evil); 
    } 
}; 

您也可以考慮將boost::optional作爲動態分配的非標準替代方案。

+0

重申「不需要做任何事」評論,不,成員變量可以徹底搞砸,如果24建設成功但分配失敗。 OP的代碼也沒有考慮到混亂的可能性,而是以更直接/更明顯的方式。智能指針解決方案似乎沒問題。 re boost :: optional,一個簡單的方法可以在沒有boost依賴的情況下做同樣的事情,就是使用std :: vector和emplace_back來進行構造嘗試。 – 2014-09-25 16:51:01

+0

@ Cheersandhth.-Alf:是的,我確實忘記了沒有提供強有力的例外保證的移動分配的可能性;但這不會是一個問題,除非它做的事情很奇怪。 – 2014-09-25 16:54:08

+0

@ Cheersandhth.-Alf:一個vector不會比'unique_ptr'提供任何優勢;該對象仍然是動態分配的。 – 2014-09-25 16:58:03