2013-02-08 19 views
7

की जांच करते समय क्या exception_ptr करता है, सी ++ 11 मानक का कहना है (18.8.5/7) कि: exception_ptr वस्तुओं है कि एक ही अपवाद वस्तु का उल्लेख एक डेटा दौड़ परिचय नहीं करेगा पर rethrow_exception कीrethrow_exception वास्तव में एक प्रतिलिपि के बजाय एक ही अपवाद वस्तु फेंक सकता है?

का प्रयोग करें। [नोट: यदि rethrow_exception एक ही अपवाद वस्तु rethrows (बल्कि एक प्रति की तुलना में), कि rethrown अपवाद वस्तु एक डेटा दौड़ परिचय हो सकता है समवर्ती पहुँच ...

मैं मामले नहीं मिल रहा है, जहां इस अजीब "ध्यान दें "लागू होता है, क्योंकि rethrow_exception का वर्णित प्रभाव" फेंकता है: अपवाद ऑब्जेक्ट जिस पर पी संदर्भित करता है "लेकिन 15.1/3, सामान्य अपवाद फेंकने की प्रक्रिया का वर्णन करने के लिए जरूरी है कि" एक अपवाद प्रतिलिपि बनाना एक अस्थायी वस्तु को प्रारंभ करता है, जिसे अपवाद वस्तु कहा जाता है। "

अजीब नोट यह इंगित करेगा कि rethrow_exception इस प्रति-प्रारंभिकरण को छोड़ देता है। लेकिन क्या यह वास्तव में संभव है?

+0

शायद यह अभी चल रहा है? –

+0

यूप, 'std :: rethrow_exception' को 'throw x;' अभिव्यक्ति का उपयोग करके कार्यान्वित नहीं किया जा सकता है। (लेकिन यह 'फेंक' जैसा ही है; 0। – aschepler

उत्तर

3

हां, यह मानक में कमी की तरह दिखता है। एक rethrowing फेंक अभिव्यक्ति अर्थात throw; एक संकार्य के बिना के लिए, 15.1p8 का कहना है:

कोई संकार्य के साथ एक फेंक अभिव्यक्ति वर्तमान में संभाला अपवाद rethrows। अपवाद मौजूदा अपवाद वस्तु के साथ पुनः सक्रिय किया गया है; कोई नई अपवाद वस्तु नहीं बनाई गई है। [...]

है:

#include <exception> 
#include <cassert> 
int main() { 
    std::exception *p = nullptr; 
    try { 
     try { 
     throw std::exception(); 
     } catch(std::exception &ex) { 
     p = &ex; 
     throw; 
     } 
    } catch(std::exception &ex) { 
     assert(p == &ex); 
    } 
} 

current_exception प्रतियां वर्तमान में संभाला अपवाद वस्तु के कार्यान्वयन, वहाँ कोई रास्ता नहीं है कि क्या rethrow_exception प्रतियां या नहीं बताने के लिए है, लेकिन अगर यह को संदर्भित करता है अपवाद वस्तु तो हम देख सकते हैं:

#include <exception> 
#include <iostream> 
int main() { 
    std::exception_ptr p; 
    try { 
     try { 
     throw std::exception(); 
     } catch(...) { 
     p = std::current_exception(); 
     std::cout << (p == std::current_exception()) << ' '; 
     std::rethrow_exception(p); 
     } 
    } catch(...) { 
     std::cout << (p == std::current_exception()) << '\n'; 
    } 
} 

हर कार्यान्वयन मैं प्रिंट 1 1 पर यह कोशिश की है; 0 0 की अनुमति है यदि current_exception प्रतियां; 0 1 स्पष्ट रूप से असंभव है, जबकि इसके वर्तमान स्थिति में मानक 1 0 की आवश्यकता होती है।फिक्स 18.8.510 के लिए 15.1p8 के समान भाषा के साथ स्पष्ट किया जाएगा, या तो rethrow_exception को exception_ptr द्वारा इंगित अपवाद ऑब्जेक्ट की प्रतिलिपि बनाने की अनुमति देने या अनुमति देने के लिए।

अधिकांश फेंकता: या अनिश्चितकालीन लेख का उपयोग (फेंकता: प्रकार की एक अपवाद ...): मानक में विनिर्देशों सिर्फ एक प्रकार का नाम (bad_allocफेंकता); निश्चित लेख का उपयोग करने के लिए एकमात्र अन्य अपवाद विनिर्देश future::get और shared_future::get हैं, इसलिए किसी भी रिज़ॉल्यूशन को शायद उनको भी संबोधित करना चाहिए।

+0

आगे की जांच के बाद, मुझे इस मामले में एक प्रतिलिपि बनाने का प्रस्ताव देने वाले एलडब्लूजी का मुद्दा मिला है (अंक # 1369)। ऐसा लगता है कि कार्यान्वयन कैसे व्यवहार करते हैं, इसकी पुष्टि करते हुए वे इसके खिलाफ बस गए हैं। मेरा मानना ​​है कि आपके द्वारा प्रस्तावित एक स्पष्टीकरण समझ में आता है, हालांकि। – soulie

2

हां, यह संभव है। अपवाद-हैंडलिंग तंत्र में पहले से ही उस ऑब्जेक्ट की प्रतिलिपि है जिसे मूल रूप से फेंक दिया गया था, जो एक निजी मेमोरी स्टैश में घिरा हुआ था। आमतौर पर, exception_ptr को एक स्मार्ट पॉइंटर के रूप में कार्यान्वित किया जाता है जो उस प्रतिलिपि के लिए संदर्भ गणना प्रबंधित करता है।

सामान्य आवश्यकताओं के अनुसार, यदि एक विशिष्ट आवश्यकता सामान्य आवश्यकता के साथ संघर्ष करती है, तो विशिष्ट आवश्यकता जीत जाती है।

+0

लेकिन AFAIK नोट मानक नहीं हैं, इसलिए पुनर्विचार को अनिवार्य नई प्रतिलिपि बनाना चाहिए। – soulie

+0

@twicker - आप सही हो सकते हैं कि यह सही ढंग से निर्दिष्ट नहीं है। '' 'अपवाद_ptr' मूल रूप से एक लाइब्रेरी-केवल एक्सटेंशन था, जिसके लिए रनटाइम अपवाद समर्थन का विस्तार आवश्यक था लेकिन कोई भाषा बदलती नहीं थी। एक नई प्रति की आवश्यकता के लिए ऑब्जेक्ट की कॉपी कन्स्ट्रक्टर को पॉइंटर स्टोर करने का एक तरीका आवश्यक होगा; जबकि यह तकनीकी रूप से व्यवहार्य है, पुराने ऑब्जेक्ट को फिर से उपयोग करना बहुत आसान है। और व्यवहार में, कोई फर्क नहीं पड़ता; आप एक कॉपी कन्स्ट्रक्टर लिख सकते हैं जो रिकॉर्ड करता है कि उसे कॉल किया गया है, लेकिन उस तरफ, यह किसी वास्तविक दुनिया कोड को प्रभावित नहीं करता है। –

3

जब आप throw x; कहते हैं, तो अपवाद ऑब्जेक्ट x जैसा ही होता है लेकिन एक प्रति है।

जब आप std::rethrow_exception(p); कहते हैं, तो अपवाद वस्तु वास्तविक वस्तु है जिसे पॉइंटर द्वारा संदर्भित किया जाता है, और कोई और प्रतियां नहीं मिलती हैं।

इस प्रकार तो वे सब एक ही वस्तु के लिए एक संदर्भ है कई सूत्र समवर्ती ही अपवाद सूचक rethrow है (जो आप कॉपी करने की अनुमति है!),।

+0

ठीक है, यह समझ में आता है। फिर भी, मानक भ्रमित है जब यह rethrow_exception के व्यवहार का वर्णन करता है "थ्रो: अपवाद ऑब्जेक्ट जिस पर पी संदर्भित करता है।" – soulie

+0

@twicker: मुझे लगता है कि यह बहुत स्पष्ट है। हमेशा "अपवाद ऑब्जेक्ट" की धारणा होती है, और 'std :: current_exception' उस ऑब्जेक्ट को पॉइंटर बनाता है। –