2012-02-12 12 views
9

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

मेरा प्रश्न यह है: मैं सीमा के एक तरफ अपवाद कैसे पकड़ सकता हूं और सी एपीआई सीमा को फिर से भरने के बाद इसे फिर से फेंक सकता हूं और निष्पादन सी ​​++ भूमि में वापस आ जाता है ताकि अपवाद को संभाला जा सके क्लाइंट कोड?

उत्तर

5

के साथ सी ++ 11 हम इस्तेमाल कर सकते हैं:

std::exception_ptr active_exception; 

try 
{ 
    // call code which may throw exceptions 
} 
catch (...) 
{ 
    // an exception is thrown. save it for future re-throwing. 
    active_exception = std::current_exception(); 
} 

// call C code 
... 

// back to C++, re-throw the exception if needed. 
if (active_exception) 
    std::rethrow_exception(active_exception); 

से पहले सी ++ 11 ये अभी भी Boost Exception के माध्यम से इस्तेमाल किया जा सकता।

+0

यदि अपवाद को मूल्य से फेंक दिया गया है, तो क्या 'upgrade_ptr' इसे जीवित रखेगा? –

+0

@ सेठ कार्नेगी: मानक से, हाँ। (§18.8.5/8 "संदर्भित वस्तु कम से कम तब तक वैध रहेगी जब तक कि 'अपवाद_प्टर' ऑब्जेक्ट होता है जो इसे संदर्भित करता है।") बूस्ट कार्यान्वयन वही करना चाहिए। – kennytm

+0

यह बहुत ही बढ़िया है, ऐसा लगता है कि कमेटी ने सी ++ 11 को दिमाग में डिजाइन किया है। यह भी कारण है कि वीएस -2010 'अपवाद_प्टर', 'current_exception' और' rethrow_exception' लागू करता है जिसे मैं इस उत्तर को स्वीकार कर सकता हूं। धन्यवाद। –

0

आप शायद सी इंटरफ़ेस में एक संरचना पास कर सकते हैं जो अपवाद के मामले में त्रुटि जानकारी से भरा हो जाता है और फिर जब क्लाइंट पक्ष पर प्राप्त होता है, तो उसे जांचें और डेटा के आधार पर क्लाइंट के अंदर अपवाद फेंक दें संरचना से। अगर आपको केवल अपवाद को फिर से बनाने के लिए न्यूनतम जानकारी की आवश्यकता है, तो आप शायद एक त्रुटि कोड के रूप में 32-बिट/64-बिट पूर्णांक का उपयोग कर सकते हैं। उदाहरण के लिए:

typedef int ErrorCode; 

... 

void CMyCaller::CallsClient() 
{ 
    CheckResult (CFunction (...)); 
} 

void CheckResult (ErrorCode nResult) 
{ 
    // If you have more information (for example in a structure) then you can 
    // use that to decide what kind of exception to throw.) 
    if (nResult < 0) 
     throw (nResult); 
} 

... 

// Client component's C interface 

ErrorCode CFunction (...) 
{ 
    ErrorCode nResult = 0; 

    try 
    { 
     ... 
    } 
    catch (CSomeException oX) 
    { 
     nResult = -100; 
    } 
    catch (...) 
    { 
     nResult = -1; 
    } 

    return (nResult); 
} 

आप एक ही int32/int64 की तुलना में अधिक जानकारी की जरूरत है तो आप कॉल करने से पहले एक संरचना का आवंटन और सी समारोह जो, बारी में, आंतरिक और अगर वे अपवाद पकड़ेगा को इसका पता पारित कर सकते हैं होता है, अपने पक्ष में एक अपवाद फेंकता है।

+0

यदि संभव हो तो मैं अपवाद खोना नहीं चाहता हूं, उदाहरण के लिए यदि उपयोगकर्ता का कॉलबैक अपने स्वयं के अपवाद को फेंकता है तो मैं इसे –

+0

@ सेठ कार्नेगी फेंकना चाहूंगा यदि आप मॉड्यूल सीमाओं को पार कर रहे हैं (मुझे लगता है कि आप करते हैं , अन्यथा यह पूरी बात कोई मुद्दा नहीं होगी) तो मुझे वास्तविक अपवाद जानकारी को संरक्षित करने का कोई तरीका नहीं दिखता है। एक और जटिलता यह है कि सी ++ किसी भी प्रकार को अपवाद होने की इजाजत देता है ताकि यदि आप इसे संरक्षित करना चाहते हैं, तो आपको यह जानना होगा कि किस प्रकार के हैंडल करना है। यदि सभी अपवादों को 'std :: अपवाद' डेरिवेटिव होने की गारंटी है, तो यह बहुत कठिन नहीं हो सकता है लेकिन यदि किसी भी प्रकार की अनुमति है, तो यह चीजों को बदल देता है। – xxbbcc

3

कुछ वातावरण इस कम या ज्यादा सीधे समर्थन करते हैं।

उदाहरण के लिए, यदि आप structured exception handling और सी ++ /EH संकलक स्विच के माध्यम से अपवाद सक्षम है, तो आप सी ++ अपवाद माइक्रोसॉफ्ट के संरचित अपवाद हैंडलिंग (सी के लिए "अपवाद") से अधिक लागू किया हो सकता है। बशर्ते ये विकल्प आपके सभी कोड संकलित करते समय सेट हो जाएं (प्रत्येक छोर पर सी ++ और बीच में सी) अवांछित ढेर "काम" करेगा।

हालांकि, यह लगभग हमेशा एक बुरा विचार (टीएम) होता है। क्यों, आप पूछते हैं? विचार करें कि बीच में सी कोड का टुकड़ा है:

WaitForSingleObject(mutex, ...); 
invoke_cxx_callback(...); 
ReleaseMutex(mutex); 

और वह invoke_cxx_callback() (.... ड्रम रोल ...) का आह्वान अपने सी ++ कोड है कि एक अपवाद फेंकता है। आप एक म्यूटेक्स लॉक रिसाव करेंगे। आउच।

आप देखते हैं, बात यह है कि अधिकांश सी कोड को फ़ंक्शन के निष्पादन में किसी भी पल में सी ++ - स्टाइल स्टैक को अनदेखा करने के लिए लिखा नहीं जाता है। इसके अलावा, इसमें विनाशकों की कमी है, इसलिए इसमें अपवादों से बचाने के लिए RAII नहीं है।

Kenny TM सी ++ 11 और बूस्ट-आधारित परियोजनाओं का समाधान है। xxbbcc सामान्य मामले के लिए अधिक कठिन समाधान के बावजूद अधिक सामान्य है।

+0

यह केनी टीएम के रास्ते के साथ एक गैर-मुद्दा है क्योंकि 'invoke_cxx_callback' सामान्य रूप से वापस आ जाएगा (अपवाद को' अपवाद_प्टर 'में अपवादित किया जाता है) और जब सी कोड C++ कोड पर वापस आ जाता है, तो C++ कोड जांचता है कि कोई अपवाद फेंक दिया गया था या नहीं और यदि ऐसा है तो इसे फिर से उखाड़ फेंक दें। –

+0

@ सेठ कार्नेगी: मुझे पता है, यही कारण है कि मैंने "समाधान" के लिए अन्य उत्तरों दोनों को संदर्भित किया। यह उत्तर केवल बताता है कि सी कोड के माध्यम से अपवादों के "पास से" क्यों नहीं है। –

+0

* "आपके पास माइक्रोसॉफ्ट के संरचित अपवाद हैंडलिंग पर लागू सी ++ अपवाद हो सकते हैं" * - यह सही नहीं है। माइक्रोसॉफ्ट के कंपाइलर्स ने एसईएच अपवादों के संदर्भ में हमेशा सी ++ अपवाद लागू किए हैं। वहां कोई विकल्प नहीं है। कंपाइलर स्विच केवल एमएससी द्वारा लागू अपवाद हैंडलिंग कीवर्ड के अर्थशास्त्र को नियंत्रित करता है। – IInspectable