2010-06-02 13 views
6

में अपवाद को स्टोर करने का सही तरीका मेरे पास एक एपीआई है जिसमें त्रुटि रिपोर्टिंग के लिए आंतरिक रूप से कुछ अपवाद हैं। मूल संरचना यह है कि इसमें रूट अपवाद ऑब्जेक्ट है जो std::exception से प्राप्त होता है, फिर यह उसके कुछ सबक्लास को फेंक देगा।एक चर

एक लाइब्रेरी या थ्रेड में फेंकने वाले अपवाद को पकड़ने और इसे दूसरे में पकड़ने से अपरिभाषित व्यवहार हो सकता है (कम से कम क्यूटी इसके बारे में शिकायत करता है और इसे कई संदर्भों में अस्वीकार करता है)। मैं लाइब्रेरी कॉल को फ़ंक्शंस में लपेटना चाहता हूं जो एक स्टेटस कोड वापस कर देगा, और यदि कोई अपवाद हुआ, अपवाद ऑब्जेक्ट की एक प्रति।

स्टोर बाद में उपयोग के लिए एक अपवाद (इसके पॉलीमोर्फिक व्यवहार के साथ) का सबसे अच्छा तरीका क्या है? मेरा मानना ​​है कि सी ++ 0x भविष्य एपीआई इस तरह के कुछ का उपयोग करता है। तो सबसे अच्छा तरीका क्या है?

सबसे अच्छा मैं सोच सकता हूं कि प्रत्येक अपवाद वर्ग में clone() विधि है जो एक ही प्रकार के अपवाद के लिए सूचक लौटाएगी। लेकिन यह बहुत सामान्य नहीं है और मानक अपवादों से बिल्कुल निपटता नहीं है।

कोई विचार?

EDIT: ऐसा लगता है कि सी ++ 0x a mechanism for this होगा। इसे "लाइब्रेरी जादू" के रूप में वर्णित किया गया है। क्या इसका मतलब यह है कि सी ++ 0x की किसी भी भाषा विशेषताओं की आवश्यकता नहीं है? यदि नहीं, तो क्या कोई कार्यान्वयन है जो सी ++ 03 के साथ संगत है?

EDIT: ऐसा लगता है कि बूस्ट में implementation of exception copying है। मैं किसी भी गैर boost::copy_exception उत्तरों के लिए प्रश्न खुला रखूंगा।

EDIT: स्मृति त्रुटि से बाहर अपवाद के मूल कारण के बारे में j_random_hacker की चिंताओं को संबोधित करने के लिए। इस विशेष पुस्तकालय और अपवादों के सेट के लिए, यह मामला नहीं है। रूट अपवाद ऑब्जेक्ट से व्युत्पन्न सभी अपवाद अमान्य उपयोगकर्ता इनपुट के कारण विभिन्न प्रकार की पार्सिंग त्रुटियों का प्रतिनिधित्व करते हैं। मेमोरी से संबंधित अपवादों को आसानी से std::bad_alloc फेंक दिया जाएगा जिसे अलग से संबोधित किया जाता है।

उत्तर

4

आपके पास क्या होगा जो मुझे लगता है कि आपका सबसे अच्छा, केवल जवाब है। आप मूल अपवाद का संदर्भ नहीं रख सकते क्योंकि यह गुंजाइश छोड़ने जा रहा है। आपको बस इसकी प्रतिलिपि बनाना है और ऐसा करने का एकमात्र सामान्य तरीका क्लोन() जैसे प्रोटोटाइप फ़ंक्शन के साथ है।

क्षमा करें।

+0

लेकिन सावधान रहना है कि अपवाद के मूल कारण एक आउट-ऑफ-स्मृति शर्त है, जिसमें मामले 'क्लोन()' 'अगर यह कॉल करने के लिए कोशिश करता है new' असफल हो जायेगी हो सकता है। यह चारों ओर मिल सकता है, उदा। एक स्थिर बफर से आवंटित करने के लिए प्रत्येक अपवाद प्रकार के लिए 'ऑपरेटर नया() 'ओवरलोडिंग करके, लेकिन यह आवश्यक रूप से सुंदर नहीं है। –

+0

@j_random_hacker: ठीक है, क्योंकि हम पंडिताऊ हो रही है, क्या आप बाहर के स्मृति बेहतर कहा जाता है बुरा alloc और यह स्मृति से बाहर वास्तविक होने की जरूरत नहीं है कहते हैं। बुरा alloc के लिए एक और कारण बहुत अधिक स्मृति का अनुरोध कर रहा है, और उस मामले में बाद में छोटे आवंटन – sbk

+1

@sbk सफल होगा: यह वास्तव में स्मृति से बाहर चल रहा है की संभावना पर विचार करने के लिए पंडिताऊ है? –

1

आपको पॉइंटर्स समेत कुछ भी फेंकने की अनुमति है। तुम बस

try { 

    doSomething(); // Might throw MyException* 

} catch (std::exception* pEx) { 

    // store pEx pointer 
} 

: आप हमेशा कुछ इस तरह कर सकता है:

throw new MyException(args); 

और फिर अपवाद संचालक में (यह मानते हुए कि MyExceptionstd::exception से निकला नीचे) पकड़ा सूचक है, जो पूरी तरह से बहुरूपी हो जाएगा की दुकान जब आप इसे इस तरह करते हैं तो मेमोरी लीक के बारे में सावधान रहना होगा, यही कारण है कि फेंक-बाय-वैल्यू और कैच-बाय-रेफरेंस सामान्य रूप से उपयोग किया जाता है।पकड़-दर-सूचक के बारे में

अधिक: http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.8

+1

इस समाधान के साथ समस्या यह है कि जैसा कि मैंने देखा है कि आप किसी ऐसी चीज के कारण अपवाद फेंक रहे हैं जिसके मूल कारण के कारण स्मृति की स्थिति समाप्त हो गई है, इस मामले में 'नया' असफल हो जाएगा। –

+1

इस लिंक में उल्लेख किया गया है, लेकिन आप सिद्धांत में उस मामले में फेंकने वाले प्री-आवंटित या स्थैतिक आउट-ऑफ-मेमोरी अपवाद के द्वारा काम कर सकते हैं। लेकिन फिर आपको यह सुनिश्चित करना होगा कि आप इसे हटा नहीं पाएंगे क्योंकि आप अपने अन्य अपवादों को करेंगे। यह करने योग्य है लेकिन आपको इस तरह के कई संकटों से सावधान रहना होगा। –

+0

क्या हम यह देखने के लिए जांच नहीं सकते कि अपवाद स्मृति की स्थिति से बाहर निकलता है और यह इंगित करने के लिए बस एक int/बूलियन सेट करता है? –

0

कारण है कि एक अपवाद एक पुस्तकालय में फेंक दिया को पकड़ने और एक अन्य में यह पकड़ने अपरिभाषित व्यवहार हो सकता है कि इन पुस्तकालयों अलग क्रम पुस्तकालयों के साथ जोड़ा जा सकता है है। यदि आप इसे फेंकने के बजाए फ़ंक्शन से अपवाद वापस कर देंगे तो आप उस समस्या से बच नहीं पाएंगे।

+0

मेरा मानना ​​है कि आप सही हैं, मुझे लगता है कि इस मुद्दे के साथ क्यूटी के पास थ्रेड के बीच गुजरने के बारे में अधिक जानकारी है (मैंने अपने प्रश्न के साथ उस सूक्ष्मता को भी जोड़ा है)। –

0

मेरी उपयोगिता लाइब्रेरी में AnyException कक्षा है जो मूल रूप से boost::any के रूप में कास्टिंग समर्थन के बिना होती है। इसके बजाए, इसमें Throw() सदस्य है जो मूल ऑब्जेक्ट संग्रहीत करता है।

struct AnyException { 
    template<typename E> 
    AnyException(const E& e) 
    : instance(new Exception<E>(e)) 
    { } 

    void Throw() const { 
    instance->Throw(); 
    } 

private: 
    struct ExceptionBase { 
    virtual void Throw() const =0; 
    virtual ~ExceptionBase() { } 
    }; 

    template<typename E> 
    struct Exception : ExceptionBase { 
    Exception(const E& e) 
     : instance(e) 
    { } 

    void Throw() const { 
     throw std::move(instance); 
    } 

    private: 
    E instance; 
    }; 
    ExceptionBase* instance; 
}; 

यह एक सरलीकरण है, लेकिन यह मूल रूपरेखा है। मेरा वास्तविक कोड प्रतिलिपि अक्षम करता है, और इसके बजाय अर्थशास्त्र चलाता है। आवश्यक होने पर आप ExceptionBase आसानी से पर्याप्त के लिए एक आभासी Clone विधि जोड़ सकते हैं ... के बाद से Exception वस्तु की मूल प्रकार जानता है, यह वास्तविक प्रतिलिपि निर्माता पर अनुरोध अग्रेषित कर सकते हैं, और आप तुरंत सभी copiable प्रकार के लिए समर्थन है, नहीं बस अपने Clone विधि के साथ।

जब यह डिजाइन किया गया था, यह भंडारण के लिए नहीं था अपवाद पकड़ा ... एक बार एक अपवाद फेंका गया था, यह सामान्य रूप में प्रचारित किया तो बाहर के स्मृति की स्थिति नहीं माना जाता था। हालांकि, मुझे लगता है कि आप ऑब्जेक्ट में std::bad_alloc का एक उदाहरण जोड़ सकते हैं, और इसे सीधे उन परिस्थितियों में संग्रहीत कर सकते हैं।

struct AnyException { 
    template<typename E> 
    AnyException(const E& e) { 
     try { 
      instance.excep = new Exception<E>(e); 
      has_exception = true; 
     } catch(std::bad_alloc& bad) { 
      instance.bad_alloc = bad; 
      bas_exception = false; 
     } 
    } 

    //for the case where we are given a bad_alloc to begin with... no point in even trying 
    AnyException(const std::bad_alloc& bad) { 
    instance.bad_alloc = bad; 
    has_exception = false; 
    } 

    void Throw() const { 
    if(has_exception) 
     instance.excep->Throw(); 
    throw instance.bad_alloc; 
    } 

private: 
    union { 
    ExceptionBase* excep; 
    std::bad_alloc bad_alloc; 
    } instance; 
    bool has_exception; 
}; 

मैंने वास्तव में उस दूसरे बिट का बिल्कुल परीक्षण नहीं किया है ... मुझे कुछ चमकदार रूप से स्पष्ट याद आ रहा है जो इसे काम करने से रोक देगा।