5

मैं एक छात्र हूं और मेरे पास सी ++ पर छोटा ज्ञान है, जिसे मैं विस्तार करने का प्रयास करता हूं। यह एक दार्शनिक सवाल है .. मैं कुछ लागू करने की कोशिश नहीं कर रहा हूं।नोट्रो या अपवाद?

के बाद से

#include <new> 
//... 
T * t = new (std::nothrow) T(); 
if(t) 
{ 
    //... 
} 
//... 

अपवाद को छिपाने करेंगे, और अपवाद के साथ काम कर के बाद से भारी है, एक सरल if(t) की तुलना में है यही कारण है कि सामान्य new T() नहीं माना कम अच्छा अभ्यास नहीं है, पर विचार हम try-catch() का उपयोग करना होगा यह जांचने के लिए कि क्या एक साधारण आवंटन सफल हुआ (और यदि हम नहीं करते हैं, तो बस कार्यक्रम को मरें) ??

nothrow new का उपयोग करने की तुलना में सामान्य new आवंटन के लाभ (यदि कोई हैं) क्या हैं? उस मामले में अपवाद का ओवरहेड महत्वहीन है?

यह भी मान लें कि आवंटन विफल रहता है (उदाहरण के लिए। सिस्टम में कोई स्मृति मौजूद नहीं है)। क्या ऐसी स्थिति में प्रोग्राम कुछ भी कर सकता है, या बस ग़लत ढंग से विफल हो सकता है। ढेर पर मुफ्त मेमोरी खोजने का कोई तरीका नहीं है, जब सब आरक्षित है, है ना?

बैठाना आवंटन में विफल रहता है, और एक std::bad_allocthrow n है, हम कैसे मान सकते हैं कि के बाद से वहाँ एक वस्तु आवंटित करने के लिए पर्याप्त स्मृति नहीं है (उदाहरण के लिए। एक new int), वहाँ एक अपवाद स्टोर करने के लिए पर्याप्त स्मृति होगा ??

आपके समय के लिए धन्यवाद। मुझे उम्मीद है कि सवाल नियमों के अनुरूप है।

+0

यदि उपरोक्त आपके कोड में नया विफल रहता है। यदि आप कथन में क्या करने की योजना बना रहे हैं? इस बिंदु पर त्रुटि को ठीक करने का कोई तरीका नहीं है। –

+0

@ मार्टिन, वास्तव में कुछ भी नहीं। मैं इस मामले के बारे में सिर्फ उत्सुक था और यदि 'नोट्रो' का उपयोग करने पर कोई फायदा होता है। असल में जवाब कई चीजों को स्पष्ट कर दिया। – Muggen

+1

आपने स्मृति आवंटन में एक दुर्भाग्यपूर्ण उदाहरण चुना है। आधुनिक डेस्कटॉप ओएस पर चल रहे अनुप्रयोग आम तौर पर अपवाद नहीं फेंकते हैं या स्मृति से बाहर होने पर त्रुटि संदेश लौटाते हैं।इसके बजाए, पूरी प्रणाली बस जम जाती है, जबकि ओएस धीमी भंडारण का उपयोग करके अनुरोधित स्मृति को "अनुकरण" की खोने वाली लड़ाई से लड़ता है। लेकिन अपवाद बनाम वापसी कोड का सवाल अच्छा है अगर फ़ाइल I/O, नेटवर्क एक्सेस, स्ट्रिंग पार्सिंग, या किसी अन्य कार्य पर लागू होता है। –

उत्तर

5

अपवाद के साथ काम कर के बाद से एक सरल है, तो (टी) की तुलना में भारी है, क्यों विचार कर हम try- का उपयोग करना होगा, सामान्य नई टी() कम अच्छा अभ्यास नहीं माना नहीं है पकड़ने के लिए (0) सरल आवंटन सफल हुआ (और यदि हम नहीं देखते हैं, तो प्रोग्राम को मरें देखें) ?? की तुलना में सामान्य नए आवंटन के लाभ क्या हैं (यदि कोई हैं) नया नोट का उपयोग कर क्या हैं? उस मामले में अपवाद ओवरहेड महत्वहीन है?

अपवाद का उपयोग कर के लिए जुर्माना वास्तव में बहुत भारी है, लेकिन (एक शालीनता से देखते कार्यान्वयन में) दंड केवल भुगतान किया जाता है जब एक अपवाद फेंक दिया जाता है - तो मेनलाइन मामले बहुत तेजी से रहता है, और वहाँ की संभावना नहीं है अपने उदाहरण में दोनों के बीच कोई मापनीय प्रदर्शन हो।

अपवादों का लाभ यह है कि आपका कोड सरल है: यदि कई ऑब्जेक्ट आवंटित करने के लिए आपको "आवंटित ए" नहीं करना है, यदि (ए) {आवंटित बी; यदि (बी) आदि ... "।सफाई और समाप्ति - दोनों अपवाद और मुख्य लाइन मामले में - आरएआईआई द्वारा स्वचालित रूप से संभाला जाता है (जबकि यदि आप मैन्युअल रूप से जांच रहे हैं तो आपको मैन्युअल रूप से मुफ़्त में भी जाना होगा, जिससे स्मृति को रिसाव करना बहुत आसान हो जाता है)।

यह भी मान लें कि आवंटन विफल रहता है (उदाहरण के लिए सिस्टम में कोई स्मृति मौजूद नहीं है)। क्या स्थिति कुछ भी है जो प्रोग्राम उस स्थिति में कर सकता है, या बस सुन्दरता से विफल हो सकता है। ढेर पर मुफ्त मेमोरी खोजने का कोई तरीका नहीं है, जब सभी आरक्षित हैं, है ना?

ऐसी कई चीजें हैं जो यह कर सकती हैं, और करने के लिए सबसे अच्छी बात यह है कि कार्यक्रम लिखा जा रहा है। विफल और बाहर निकलना (कृपापूर्वक या अन्यथा) निश्चित रूप से एक विकल्प है। दूसरा, अग्रिम में पर्याप्त मेमोरी आरक्षित करना है, ताकि कार्यक्रम अपने कार्यों (शायद कम कार्यक्षमता या प्रदर्शन के साथ) के साथ आगे बढ़ सके। यह अपनी कुछ याददाश्त मुक्त करने में सक्षम हो सकता है (उदाहरण के लिए यदि यह कैश को बनाए रखता है जिसे आवश्यक होने पर पुनर्निर्मित किया जा सकता है)। या (सर्वर प्रक्रिया के मामले में), सर्वर वर्तमान अनुरोध को संसाधित करने से इनकार कर सकता है (या नए कनेक्शन स्वीकार करने से इनकार कर सकता है), लेकिन चलते रहें ताकि ग्राहक अपने कनेक्शन नहीं छोड़ सकें, और चीजें स्मृति के बाद फिर से काम करना शुरू कर सकती हैं रिटर्न। या एक इंटरैक्टिव/जीयूआई अनुप्रयोग के मामले में, यह उपयोगकर्ता को एक त्रुटि प्रदर्शित कर सकता है और आगे बढ़ सकता है (उन्हें स्मृति समस्या को ठीक करने और फिर से प्रयास करने की अनुमति देता है - या कम से कम अपने काम को बचाएं!)।

बैठाना आवंटन में विफल रहता है, और एक std :: bad_alloc फेंक दिया जाता है, हम चाहते हैं कि कैसे मान कर सकते हैं के बाद से वहाँ पर्याप्त एक वस्तु आवंटित करने के लिए स्मृति नहीं है (उदाहरण के लिए। एक नई पूर्णांक), वहाँ हो जाएगा एक अपवाद स्टोर करने के लिए पर्याप्त स्मृति ??

नहीं, आमतौर पर मानक पुस्तकालय सुनिश्चित करेंगे कि आम तौर पर स्मृति की थोड़ी मात्रा आवंटित करके, स्मृति में समाप्त होने की स्थिति में अपवाद के लिए पर्याप्त स्मृति होगी।

+2

अपवादों की लागत सामान्य कोड प्रवाह से अधिक है लेकिन भारी भार वाला शब्द है। मैं शर्त लगाता हूं कि 10 फ़ंक्शन कॉल अपवाद फेंकने की लागत फ़ंक्शन कॉल की दस परतों के माध्यम से त्रुटि कोड को पास करने के समान होती है जहां इसे संभाला जा सकता है। फिर भी कोड अधिक सहज और साफ है (जब अपवादों का उपयोग किया जा रहा है) –

+0

@ मार्टिन यॉर्क: आप सही हैं, "भारी" वास्तव में एक भारित शब्द है :) लेकिन इस तरह के सामान्य प्रश्नों से निपटने के दौरान और अधिक विशिष्ट होना मुश्किल है - सटीक जुर्माना कार्यान्वयन, मंच, और उन दस फ़ंक्शन कॉलों की संख्या पर निर्भर करेगा जो अपवाद को पकड़ और फिर से फेंक देते हैं। आप शर्त लगा सकते हैं कि लागत वही होगी, और आप सही हो सकते हैं; अगर मैं ऐसी परिस्थिति में था जहां मैंने अंतर के बारे में काफी परवाह की थी तो मैं इसे मापूंगा :-) – psmears

+0

@ मार्टिन: अपवाद बेहद महंगा हैं। मुझे आश्चर्य होगा अगर दस रिटर्न मूल्यों की जांच अपवाद की तुलना में भी ध्यान देने योग्य थी। यह 100,000 सफल संचालन के दौरान उन दस रिटर्न मूल्यों की जांच कर रहा है जो अपवाद से भी बदतर हैं। इसलिए, उपयोगकर्ता द्वारा प्रदत्त डेटा के सत्यापन के लिए, वापसी मूल्यों को प्राथमिकता दी जानी चाहिए, क्योंकि विफलता अपेक्षाकृत अक्सर होती है। नेटवर्क ऑपरेशंस, फिर से अपेक्षाकृत बार विफल हो जाते हैं, इसलिए वापसी मूल्यों के साथ जाएं। आवंटन, कभी विफल नहीं ***, तो अपवाद के साथ जाओ। [*** फुटनोट: अधिकांश सिस्टम थकाऊ पता स्थान से पहले मौत का पृष्ठ देंगे] –

2

अपवादों के आसपास जा रहे हैं क्योंकि वे "बहुत महंगा" समयपूर्व अनुकूलन है। अगर कोई अपवाद नहीं फेंक दिया जाता है तो कोशिश/पकड़ का व्यावहारिक रूप से कोई उपर नहीं होता है।

क्या प्रोग्राम है जो स्थिति

आम तौर पर नहीं में कुछ कर सकते हैं। अगर सिस्टम में कोई स्मृति नहीं है, तो आप शायद लॉग पर कुछ भी लिख नहीं सकते हैं, या stdout, या कुछ भी प्रिंट नहीं कर सकते हैं। यदि आप स्मृति से बाहर हैं, तो आप बहुत खराब हैं।

+0

'समयपूर्व अनुकूलन' तर्क एक पिछली शताब्दी का नारा है जो किसी भी मौका देने से पहले किसी भी उचित चर्चा को मार देता है। उदाहरण के लिए, समय-महत्वपूर्ण वातावरण में जहां स्थिरता कुंजी है, आप वास्तव में अज्ञात अपवाद हैंडलिंग का एक गुच्छा अपने सॉफ़्टवेयर के प्रवाह को नष्ट नहीं करना चाहते हैं। – StarShine

+0

@StarShine: यह एक सभ्य तर्क है। लेकिन सामान्य मामले में अपवाद "बहुत महंगी" होने की बात नहीं है जिसके बारे में आपको चिंता करनी चाहिए। – Falmarri

+0

मुझे एक बार आपके कथन से सहमत होने के लिए सिखाया गया था, लेकिन 1 के बारे में क्या सोचना है) 'सामान्य मामला' तेजी से सी ++ और 2 के उपयोग की गारंटी नहीं देता है) अर्थात् अर्थात् 'अपवाद' के अनुसार क्या भिन्न होता है आपका माइलेज/प्रोग्रामिंग भाषा। मेरा मतलब है, सिद्धांत अच्छा है, और अगर विकास एक ही चीज़ समझता है तो यह विकास के समय को बचा सकता है। अभ्यास में .. – StarShine

2

मुझे लगता है कि आप nothrow के बजाय नियमित new का उपयोग क्यों करेंगे, इस कारण से जुड़ा हुआ है कि अपवाद आमतौर पर प्रत्येक फ़ंक्शन के वापसी मूल्य को स्पष्ट रूप से जांचने के लिए क्यों पसंद किए जाते हैं। स्मृति को आवंटित करने की आवश्यकता वाले प्रत्येक फ़ंक्शन को यह नहीं पता कि अगर कोई स्मृति नहीं मिल पाती है तो क्या करना है। उदाहरण के लिए, एक गहराई से घिरा हुआ फ़ंक्शन जो स्मृति को कुछ एल्गोरिदम के लिए सबराउटिन के रूप में आवंटित करता है, शायद यह नहीं पता कि स्मृति को नहीं मिलने पर कार्रवाई का उचित तरीका क्या है। new के एक संस्करण का उपयोग करके जो अपवाद फेंकता है वह कोड को अनुमति देता है जो सबराउटिन को कॉल करता है, न कि सबराउटिन स्वयं, कार्रवाई का एक और उचित पाठ्यक्रम लेने के लिए। यह कुछ भी करने और कार्यक्रम को मरने के रूप में सरल हो सकता है (यदि आप एक छोटे खिलौने कार्यक्रम लिख रहे हैं तो पूरी तरह से ठीक है), या स्मृति को फेंकना शुरू करने के लिए कुछ उच्च स्तरीय कार्यक्रम निर्माण को सिग्नल करना।

आपके प्रश्न के उत्तरार्ध के संबंध में, वास्तव में ऐसी चीजें हो सकती हैं जो आप कर सकते हैं यदि आपका प्रोग्राम स्मृति से बाहर हो गया है जो स्मृति को और अधिक उपलब्ध कराएगा। उदाहरण के लिए, आपके पास आपके प्रोग्राम का एक हिस्सा हो सकता है जो पुराने डेटा को कैश करता है, और जैसे ही संसाधनों को तंग हो जाता है, कैश को सब कुछ बेदखल करने के लिए कह सकता है। आप डिस्क पर कुछ कम महत्वपूर्ण डेटा को संभावित रूप से पृष्ठ पर ला सकते हैं, जो शायद आपकी स्मृति से अधिक जगह है।इस तरह की चाल का पूरा समूह है, और अपवादों का उपयोग करके कार्यक्रम के शीर्ष पर सभी आपातकालीन तर्क डालना संभव है, और उसके बाद केवल उस कार्यक्रम का हर भाग है जो आवंटन को bad_alloc को पकड़ नहीं लेता है और इसके बजाए इसे छोड़ देता है शीर्ष तक फैलाना।

आखिरकार, स्मृति को दुर्लभ होने पर भी अपवाद फेंकना संभव है। कई सी ++ कार्यान्वयन अपवादों के लिए स्टैक (या कुछ अन्य गैर-ढेर मेमोरी सेगमेंट) में कुछ स्थान आरक्षित करते हैं, इसलिए यदि ढेर अंतरिक्ष से बाहर हो जाता है तो अपवादों के लिए स्मृति ढूंढना संभव हो सकता है।

आशा है कि इससे मदद मिलती है!

-2

सिम्बियन सी ++ में यह दूसरी तरफ काम करता है। आप एक अपवाद फेंका चाहते हैं OOM आप

T* t = new(ELeave) T(); 

क्या करना है और आप सही कोई नया अपवाद फेंक जब OOM अजीब होने का तर्क के बारे में कर रहे हैं जब। एक परिदृश्य जो प्रबंधनीय है अचानक एक कार्यक्रम समाप्त हो जाता है।

+2

यह केवल इतना बताता है कि सिम्बियन सी ++ वास्तव में एक मानक सी ++ नहीं है। अब, अपवादों के बजाय त्रुटि कोड के लिए बहस करना बहुत पुराना है और बार-बार गलत साबित हुआ था। एक संक्षिप्त सारांश यहां पाया जा सकता है: http://www.boost.org/community/exception_safety.html –

+0

गलत? लॉल, यह बहस की तरह है कि स्टिक-शिफ्ट कार ट्रांसमिशन गलत हैं – James

1

स्मृति से बाहर चलना एक दुर्लभ घटना होने की उम्मीद है, इसलिए जब ऐसा होता है तो अपवाद फेंकने का उपर कोई समस्या नहीं है। कार्यान्वयन std::bad_alloc फेंकने के लिए आवश्यक स्मृति को "पूर्व-आवंटित" कर सकता है, यह सुनिश्चित करने के लिए कि यह तब भी उपलब्ध है जब प्रोग्राम अन्यथा स्मृति से बाहर हो।

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

अगर वे अपवाद फेंकते हैं तो आउट-ऑफ-मेमोरी स्थितियों के लिए हैंडलिंग कोड लिखना भी आसान है: प्रत्येक आवंटन के परिणाम को अलग-अलग जांचने के बजाय, आप catch कॉल को ओओएम पकड़ने के लिए कहीं भी कॉल स्टैक में डाल सकते हैं कार्यक्रम के दौरान कई जगहों की स्थितियां।

5

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

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

इन सबके कारण, नोट्रो महत्वपूर्ण अनुप्रयोगों के लिए एक सुरक्षित समाधान प्रदान करते हैं।

संबंधित मुद्दे