दिलचस्प पोस्ट
एसक्यूएल ओरडिनल स्थिति नोटेशन का उपयोग करने के लाभ? जावास्क्रिप्ट एक ईमेल संदेश में समर्थित है? एकाधिक गतिविधियों के साथ Google प्लस साइन इन का सही उपयोग कैसे करें? अकेले प्रक्रिया को समर्पित संपूर्ण एक कोर यदि फ़ंक्शन ए केवल फ़ंक्शन बी के द्वारा आवश्यक है तो क्या बी में परिभाषित किया जाना चाहिए? चाय परीक्षण सरणी समानता अपेक्षा के अनुरूप काम नहीं करती है Laravel जल्दी शुरू गाइड मार्ग काम नहीं कर रहा है जावास्क्रिप्ट देरी फ़ंक्शन कैसे बनाएं स्ट्रीम से एक बाइट सरणी बनाना jQuery के एचटीएमएल विशेषता IE में काम नहीं कर रहा है जावास्क्रिप्ट: रद्द करें / छवि अनुरोध बंद करो पहले 10000 प्रमुख संख्याओं के लिए सबसे कुशल कोड? सी कोड को एक आलेख स्वचालित रूप से एक ग्राफ बनाना पृष्ठभूमि में ऐप करते समय पुश सूचना के साथ बैज अपडेट करें Variadic पुनरावर्ती पूर्वप्रक्रमक मैक्रोज – क्या यह संभव है?

क्या सी ++ समर्थन अंततः 'ब्लॉकों? (और यह 'आरएआई' क्या है जिसके बारे में मैं सुन रहा हूं?)

क्या सी ++ समर्थन अंततः 'ब्लॉकों?

आरएआईआईडीआईओएम क्या है?

सी ++ के आरएआई मुहावरी और सी # के 'प्रयोग' कथन में क्या अंतर है?

Solutions Collecting From Web of "क्या सी ++ समर्थन अंततः 'ब्लॉकों? (और यह 'आरएआई' क्या है जिसके बारे में मैं सुन रहा हूं?)"

नहीं, C ++ अंत में 'ब्लॉक' का समर्थन नहीं करता इसका कारण यह है कि सी ++ के बजाय आरएआईआई का समर्थन करता है: "संसाधन अधिग्रहण प्रारंभिक है" – वास्तव में उपयोगी अवधारणा के लिए एक खराब नाम

विचार यह है कि किसी वस्तु के नाशक संसाधनों को मुक्त करने के लिए जिम्मेदार है। जब ऑब्जेक्ट में स्वत: भंडारण की अवधि होती है, तो ऑब्जेक्ट के डिस्ट्रक्टर को तब बुलाया जाएगा, जब वह ब्लॉक जिसमें इसे बनाया गया था – तब भी जब उस ब्लॉक को किसी अपवाद की उपस्थिति में बाहर किया गया हो। यहां विषय के बर्जने स्ट्राउटस्ट्रैप की व्याख्या है।

आरएआईआई के लिए एक सामान्य उपयोग एक म्यूट एक्स लॉक कर रहा है:

// A class with implements RAII class lock { mutex &m_; public: lock(mutex &m) : m_(m) { m.acquire(); } ~lock() { m_.release(); } }; // A class which uses 'mutex' and 'lock' objects class foo { mutex mutex_; // mutex for locking 'foo' object public: void bar() { lock scopeLock(mutex_); // lock object. foobar(); // an operation which may throw an exception // scopeLock will be destructed even if an exception // occurs, which will release the mutex and allow // other functions to lock the object and run. } }; 

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

उन familliar के लिए C # या VB.NET के साथ, आप मान सकते हैं कि RAII IDisposable और 'का प्रयोग' कथन का उपयोग करते हुए .NET नियतात्मक विनाश के समान है। दरअसल, दो तरीकों बहुत समान हैं। मुख्य अंतर यह है कि आरएआईई ने किसी भी प्रकार के संसाधनों को निश्चित रूप से रिलीज़ किया होगा – स्मृति सहित जब .NET (यहां तक ​​कि। NET भाषा सी ++ / सीएलआई) में IDisposable को कार्यान्वित किया जाता है, तो संसाधनों को स्मृति के अलावा निर्णायक रूप से जारी किया जाएगा। .NET में, स्मृति निश्चित रूप से जारी नहीं की जाती है; मेमोरी केवल कचरा संग्रह चक्रों के दौरान रिलीज़ की जाती है।

† कुछ लोगों का मानना ​​है कि "विनाश संसाधन राहत है" आरएआईआई मुहावरों के लिए एक अधिक सटीक नाम है

सी ++ में आरएआई के अंत में आखिरकार जरूरी नहीं है

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

इसके अलावा आईएमओ कोड नीपर दिखता है (नीचे देखें)

उदाहरण:

एक डेटाबेस ऑब्जेक्ट यह सुनिश्चित करने के लिए कि डीबी कनेक्शन का उपयोग किया जाता है, इसे खोला जाना चाहिए और बंद होना चाहिए। RAII का उपयोग करके यह कन्स्ट्रक्टर / डिस्ट्रिक्टर में किया जा सकता है।

सीए + आरएआई की तरह

 void someFunc() { DB db("DBDesciptionString"); // Use the db object. } // db goes out of scope and destructor closes the connection. // This happens even in the presence of exceptions. 

आरएआईआई के उपयोग से डीबी वस्तु का उपयोग सही ढंग से बहुत आसान होता है। डीबी ऑब्जेक्ट एक विनाशक के उपयोग से सही ढंग से खुद को बंद कर देगी, फिर चाहे हम कोशिश करते हैं और इसका दुरुपयोग करते हैं।

जावा की तरह अंत में

 void someFunc() { DB db = new DB("DBDesciptionString"); try { // Use the db object. } finally { // Can not rely on finaliser. // So we must explicitly close the connection. try { db.close(); } catch(Throwable e) { /* Ignore */ // Make sure not to throw exception if one is already propagating. } } } 

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

इसके अलावा यह एक सरल उदाहरण है।
जब आपके पास कई संसाधन हैं जिनके लिए कोड जारी किया जाना जटिल हो सकता है।

एक अधिक विस्तृत विश्लेषण यहां पाया जा सकता है: http://accu.org/index.php/journals/236

सी ++ 11 में, यदि आवश्यक हो, आरएआईआई आखिरकार बनाने की अनुमति देता है:

 namespace detail { //adapt to your "private" namespace template <typename F> struct FinalAction { FinalAction(F f) : clean_{f} {} ~FinalAction() { if(enabled_) clean_(); } void disable() { enabled_ = false; }; private: F clean_; bool enabled_{true}; }; } template <typename F> detail::FinalAction<F> finally(F f) { return detail::FinalAction<F>(f); } 

उपयोग के उदाहरण:

 #include <iostream> int main() { int* a = new int; auto delete_a = finally([a] { delete a; std::cout << "leaving the block, deleting a!\n"; }); std::cout << "doing something ...\n"; } 

उत्पादन होगा:

 doing something... leaving the block, deleting a! 

सी ++ प्रोग्राम में POSIX फ़ाइल डिस्क्रिप्टर को बंद करने के लिए व्यक्तिगत तौर पर मैंने यह कई बार उपयोग किया था

संसाधनों का प्रबंधन करने वाले वास्तविक वर्ग के होने और ऐसा किसी भी प्रकार की लीक से बचा जाता है आमतौर पर बेहतर होता है, लेकिन यह अंततः उन मामलों में उपयोगी होता है जहां क्लास को ओवरकिल जैसा लगता है।

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

एक और उदाहरण:

  [...] auto precision = std::cout.precision(); auto set_precision_back = finally( [precision, &std::cout]() { std::cout << std::setprecision(precision); } ); std::cout << std::setprecision(3); 

अक्षम सदस्य उपयोगी है यदि अंत में केवल विफलता के मामले में ही कॉल किया जाना चाहिए। उदाहरण के लिए, आपको एक ऑब्जेक्ट को तीन अलग-अलग कंटेनरों में प्रतिलिपित करना होगा, आखिरकार आप प्रत्येक प्रति को पूर्ववत करने के लिए सेट कर सकते हैं और सभी प्रतिलिपि सफल होने के बाद अक्षम कर सकते हैं। ऐसा करने से, यदि विनाश नहीं फेंक सकता है, तो आप मजबूत गारंटी सुनिश्चित करते हैं

अक्षम उदाहरण:

 //strong guarantee void copy_to_all(BIGobj const& a) { first_.push_back(a); auto undo_first_push = finally([first_&] { first_.pop_back(); }); second_.push_back(a); auto undo_second_push = finally([second_&] { second_.pop_back(); }); third_.push_back(a); //no necessary, put just to make easier to add containers in the future auto undo_third_push = finally([third_&] { third_.pop_back(); }); undo_first_push.disable(); undo_second_push.disable(); undo_third_push.disable(); } 

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

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

ऐसा क्यों है कि यहां तक ​​कि कचरा कलेक्टर द्वारा स्वचालित रूप से वितरण के संसाधनों के बावजूद भी प्रबंधित भाषाओं अंत-ब्लॉक प्रदान करती हैं?

असल में, कचरा लेने वाले कलेक्टरों पर आधारित भाषाओं को "अंत में" और अधिक की आवश्यकता होती है। एक कचरा कलेक्टर आपके ऑब्जेक्ट को समय पर नहीं नष्ट करता है, इसलिए इसे गैर-मेमोरी संबंधित मुद्दों को सही ढंग से साफ करने के लिए भरोसा नहीं किया जा सकता है।

गतिशील रूप से आवंटित डेटा के संदर्भ में, बहुत से तर्क होगा कि आपको स्मार्ट पॉइंटर्स का प्रयोग करना चाहिए।

तथापि…

आरएआईआई ने उपयोगकर्ता के ऑब्जेक्ट से डिजाइनर को अपवाद सुरक्षा की जिम्मेदारी ले ली है

अफसोस की बात यह है कि यह अपनी ही गिरावट है। पुरानी सी प्रोग्रामिंग वाला मज़बूत होता है। जब आप सी या बहुत सी शैली में लिखे गए एक पुस्तकालय का उपयोग कर रहे हैं, तो आरएआईआई का उपयोग नहीं किया जाएगा। संपूर्ण एपीआई फ्रंट-एंड को फिर से लिखना, यह ठीक है कि आपको इसके साथ काम करना है। फिर "आखिरकार" की कमी वास्तव में काटती है

ऐसे पुराने धागे को खुदाई करने के लिए क्षमा करें, लेकिन निम्नलिखित तर्क में एक बड़ी त्रुटि है:

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

अधिक बार नहीं, आपको गतिशील रूप से आवंटित वस्तुओं, ऑब्जेक्ट्स की गतिशील संख्या आदि से निपटना होगा। कोशिश-ब्लॉक के अंदर, कुछ कोड कई ऑब्जेक्ट्स बना सकता है (कितने रनटाइम पर निर्धारित होते हैं) और सूची में उन्हें पॉइंट्स स्टोर करें। अब, यह एक विदेशी परिदृश्य नहीं है, लेकिन बहुत आम है। इस मामले में, आप सामान की तरह लिखना चाहते हैं

 void DoStuff(vector<string> input) { list<Foo*> myList; try { for (int i = 0; i < input.size(); ++i) { Foo* tmp = new Foo(input[i]); if (!tmp) throw; myList.push_back(tmp); } DoSomeStuff(myList); } finally { while (!myList.empty()) { delete myList.back(); myList.pop_back(); } } } 

बेशक, सूची से बाहर जाने के बाद सूची को नष्ट कर दिया जाएगा, लेकिन यह आपके द्वारा बनाए गए अस्थायी वस्तुओं को साफ नहीं करेगा।

इसके बजाय, आपको बदसूरत मार्ग पर जाना होगा:

 void DoStuff(vector<string> input) { list<Foo*> myList; try { for (int i = 0; i < input.size(); ++i) { Foo* tmp = new Foo(input[i]); if (!tmp) throw; myList.push_back(tmp); } DoSomeStuff(myList); } catch(...) { } while (!myList.empty()) { delete myList.back(); myList.pop_back(); } } 

इसके अलावा: यह भी क्यों है कि लेनदेन का संचालन किसी भी तरह से कचरा कलेक्टर द्वारा स्वचालित रूप से रद्द किए जा रहे संसाधनों के बावजूद अंत-ब्लॉक प्रदान करता है?

संकेत: अधिक है आप "अंत में" केवल स्मृति deallocation की तुलना में कर सकते हैं

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

 int CMyApp::Run() { __try { int i = CWinApp::Run(); m_Exitok = MAGIC_EXIT_NO; return i; } __finally { if (m_Exitok != MAGIC_EXIT_NO) FaultHandler(); } } 

मैंने इसे अतीत में इस्तेमाल किया है जैसे कि बाहर निकलने से पहले खुली फाइलों के बैकअप को बचाने के लिए। कुछ जेआईटी डीबगिंग सेटिंग हालांकि इस तंत्र को तोड़ देंगे।

वास्तव में नहीं, लेकिन आप उन्हें कुछ का विस्तार कर सकते हैं, उदाहरण के लिए:

 int * array = new int[10000000]; try { // Some code that can throw exceptions // ... throw std::exception(); // ... } catch (...) { // The finally-block (if an exception is thrown) delete[] array; // re-throw the exception. throw; } // The finally-block (if no exception was thrown) delete[] array; 

ध्यान दें कि मूल अपवाद फिर से फेंकने के साथ-साथ मूल अपवाद को छोड़कर अंत में-ब्लॉक खुद अपवाद फेंक सकता है यह एक सटीक समान व्यवहार है जो अंततः जावा में है। इसके अलावा, आप कोशिश के अंदर return उपयोग नहीं कर सकते हैं और ब्लॉकों को पकड़ सकते हैं।

मैं finally मैक्रो के साथ आया था जिसका उपयोग लगभग जावा में finally कीवर्ड के समान किया जा सकता है; यह std::exception_ptr और दोस्तों, लैम्ब्डा फ़ंक्शंस और std::promise , इसलिए इसे C++11 या इसके बाद के संस्करण की आवश्यकता C++11 ; यह भी यौगिक कथन अभिव्यक्ति जीसीसी एक्सटेंशन का उपयोग करता है, जो झुमक द्वारा भी समर्थित है

चेतावनी : इस उत्तर के पहले संस्करण में कई अवधारणाओं के साथ अवधारणा के एक अलग कार्यान्वयन का इस्तेमाल किया गया था।

सबसे पहले, एक सहायक वर्ग को परिभाषित करें।

 #include <future> template <typename Fun> class FinallyHelper { template <typename T> struct TypeWrapper {}; using Return = typename std::result_of<Fun()>::type; public: FinallyHelper(Fun body) { try { execute(TypeWrapper<Return>(), body); } catch(...) { m_promise.set_exception(std::current_exception()); } } Return get() { return m_promise.get_future().get(); } private: template <typename T> void execute(T, Fun body) { m_promise.set_value(body()); } void execute(TypeWrapper<void>, Fun body) { body(); } std::promise<Return> m_promise; }; template <typename Fun> FinallyHelper<Fun> make_finally_helper(Fun body) { return FinallyHelper<Fun>(body); } 

तो वास्तविक मैक्रो है

 #define try_with_finally for(auto __finally_helper = make_finally_helper([&] { try #define finally }); \ true; \ ({return __finally_helper.get();})) \ /***/ 

इसका उपयोग इस प्रकार किया जा सकता है:

 void test() { try_with_finally { raise_exception(); } catch(const my_exception1&) { /*...*/ } catch(const my_exception2&) { /*...*/ } finally { clean_it_all_up(); } } 

std::promise प्रयोग से इसे लागू करना बहुत आसान होता है, लेकिन यह शायद अनावश्यक ओवरहेड का भी एक छोटा सा हिस्सा पेश करता है जो std::promise से केवल आवश्यक कार्यों में सुधार करने से बचा जा सकता है।


¹ सीवेईटी: कुछ चीजें हैं जो finally में जावा संस्करण की तरह काम नहीं करती हैं। मेरे सर के ऊपर से चला गया:

  1. किसी बाहरी लूप से break कथन से तोड़ना संभव नहीं है, try और catch() के ब्लॉक के भीतर से, क्योंकि वे लैम्ब्डा समारोह में रहते हैं;
  2. try बाद कम से कम एक catch() ब्लॉक होना चाहिए: यह एक सी ++ आवश्यकता है;
  3. अगर फ़ंक्शन में शून्य के अलावा अन्य का रिटर्न वैल्यू होता है, लेकिन try और catch()'s ब्लॉक के भीतर कोई रिटर्न नहीं है, तो संकलन विफल हो जाएगा क्योंकि finally मैक्रो उस कोड में विस्तार होगा जो कि void को वापस करना चाहता है। ऐसा हो सकता है, गलती हो, एक finally_noreturn मैक्रो प्रकार के द्वारा एक शून्य एड हो सकता है।

सब कुछ, मुझे नहीं पता है कि क्या मैं कभी भी यह सामान स्वयं का उपयोग करूँगा, लेकिन यह इसके साथ मज़ेदार था। 🙂

जैसा कि बहुत से लोग कहते हैं, अंत में ब्लॉकों से बचने के लिए इसका समाधान सी ++ 11 सुविधाओं का उपयोग करना है। सुविधाओं में से एक unique_ptr

यहां मेफेन के जवाब में आरएआई के पैटर्न का इस्तेमाल किया गया है।

 #include <vector> #include <memory> #include <list> using namespace std; class Foo { ... }; void DoStuff(vector<string> input) { list<unique_ptr<Foo> > myList; for (int i = 0; i < input.size(); ++i) { myList.push_back(unique_ptr<Foo>(new Foo(input[i]))); } DoSomeStuff(myList); } 

सी ++ स्टैंडर्ड लाइब्रेरी कन्टेनर के साथ अनन्य_पीटआर का उपयोग करने के लिए कुछ और परिचय यहाँ है

मैं एक विकल्प प्रदान करना चाहूंगा

यदि आप चाहते हैं कि अंत में हमेशा से कॉल करने के लिए ब्लॉक करें, तो इसे अंतिम कैच ब्लॉक के बाद रख दें (जो संभवत: catch( ... ) को ज्ञात अपवाद नहीं पकड़ना चाहिए)

 try{ // something that might throw exception } catch( ... ){ // what to do with uknown exception } //final code to be called always, //don't forget that it might throw some exception too doSomeCleanUp(); 

यदि आप अंततः आखिरी चीज के रूप में ब्लॉक करना चाहते हैं जब किसी अपवाद को फेंक दिया जाता है तो आप बूलियन लोकल वैरिएबल का उपयोग कर सकते हैं – इससे पहले कि आप इसे गलत पर सेट करें और सही ब्लॉक पर बहुत ही अंत में सही असाइनमेंट करें, फिर कैरे ब्लॉक चेक के बाद चर के लिए मूल्य:

 bool generalAppState = false; try{ // something that might throw exception //the very end of try block: generalAppState = true; } catch( ... ){ // what to do with uknown exception } //final code to be called only when exception was thrown, //don't forget that it might throw some exception too if( !generalAppState ){ doSomeCleanUpOfDirtyEnd(); } //final code to be called only when no exception is thrown //don't forget that it might throw some exception too else{ cleanEnd(); } 

मेरे पास एक प्रयोग का मामला है, जहां मुझे लगता है कि finally सी + 11 भाषा का एक पूर्णतः स्वीकार्य हिस्सा होना चाहिए , क्योंकि मुझे लगता है कि प्रवाह के दृष्टिकोण से पढ़ना आसान है। मेरा उपयोग मामला उपभोक्ता / उत्पादक धागा की श्रृंखला है, जहां सभी थ्रेड्स को बंद करने के लिए चलने के अंत में एक nullptr भेजा जाता है।

यदि सी + + इसे समर्थित है, तो आप चाहते हैं कि आपका कोड ऐसा दिखता है:

  extern Queue downstream, upstream; int Example() { try { while(!ExitRequested()) { X* x = upstream.pop(); if (!x) break; x->doSomething(); downstream.push(x); } } finally { downstream.push(nullptr); } } 

मुझे लगता है कि यह अधिक तार्किक है कि लूप की शुरुआत में आखिरकार घोषणा करने के बाद से यह लूप के बाहर आने के बाद हुआ था … लेकिन यह सोचने की इच्छा है क्योंकि हम इसे सी ++ में नहीं कर सकते ध्यान दें कि कतार की downstream किसी अन्य धागे से जुड़ा है, इसलिए आप downstream के डिस्ट्रक्टर में push(nullptr) नहीं डाल सकते क्योंकि यह इस बिंदु पर नष्ट नहीं किया जा सकता है … इसे दूसरे तक जीवित रहने की आवश्यकता है धागे nullptr प्राप्त करता है

तो ऐसा करने के लिए लैम्ब्डा के साथ एक RAII क्लास का उपयोग कैसे किया जाता है:

  class Finally { public: Finally(std::function<void(void)> callback) : callback_(callback) { } ~Finally() { callback_(); } std::function<void(void)> callback_; }; 

और यहां बताया गया है कि आप इसका उपयोग कैसे करते हैं:

  extern Queue downstream, upstream; int Example() { Finally atEnd([](){ downstream.push(nullptr); }); while(!ExitRequested()) { X* x = upstream.pop(); if (!x) break; x->doSomething(); downstream.push(x); } } 

सी ++ 11 लैम्ब्डा फ़ंक्शंस का उपयोग करके एक और "आखिरकार" ब्लॉक इम्यूलेशन

 template <typename TCode, typename TFinallyCode> inline void with_finally(const TCode &code, const TFinallyCode &finally_code) { try { code(); } catch (...) { try { finally_code(); } catch (...) // Maybe stupid check that finally_code mustn't throw. { std::terminate(); } throw; } finally_code(); } 

चलो आशा करते हैं कि कंपाइलर इसके बाद के संस्करण का अनुकूलन करेगा।

अब हम इस तरह से कोड लिख सकते हैं:

 with_finally( [&]() { try { // Doing some stuff that may throw an exception } catch (const exception1 &) { // Handling first class of exceptions } catch (const exception2 &) { // Handling another class of exceptions } // Some classes of exceptions can be still unhandled }, [&]() // finally { // This code will be executed in all three cases: // 1) exception was not thrown at all // 2) exception was handled by one of the "catch" blocks above // 3) exception was not handled by any of the "catch" block above } ); 

यदि आप चाहते हैं कि आप इस मुहावरे को "प्रयास करें – आखिरकार" मैक्रोज़ में लपेटें:

 // Please never throw exception below. It is needed to avoid a compilation error // in the case when we use "begin_try ... finally" without any "catch" block. class never_thrown_exception {}; #define begin_try with_finally([&](){ try #define finally catch(never_thrown_exception){throw;} },[&]() #define end_try ) // sorry for "pascalish" style :( 

अब "अंत में" ब्लॉक सी ++ 11 में उपलब्ध है:

 begin_try { // A code that may throw } catch (const some_exception &) { // Handling some exceptions } finally { // A code that is always executed } end_try; // Sorry again for this ugly thing 

व्यक्तिगत रूप से मुझे "आखिरकार" मुहावरे के "मैक्रो" संस्करण पसंद नहीं है और वह शुद्ध "साथ-अंतिम" फ़ंक्शन का उपयोग करना पसंद करता है, हालांकि उस स्थिति में एक वाक्य रचना अधिक भारी होती है।

आप यहां पर कोड का परीक्षण कर सकते हैं: http://coliru.stacked-crooked.com/a/1d88f64cb27b3813

 try { ... goto finally; } catch(...) { ... goto finally; } finally: { ... }