क्या C ++ प्रोग्राम को सभी अपवादों को पकड़ना चाहिए और पिछले मुख्य () को बुदबुदाने से अपवादों को रोकना चाहिए?


29

मुझे एक बार सलाह दी गई थी कि एक C ++ प्रोग्राम को अंततः सभी अपवादों को पकड़ना चाहिए। उस समय दिया गया तर्क अनिवार्य रूप से ऐसे कार्यक्रम थे जो अपवादों को main()एक अजीब ज़ोंबी राज्य में प्रवेश करने से बाहर बुलबुले बनाने की अनुमति देते हैं । मुझे यह कई साल पहले बताया गया था और पूर्वव्यापीकरण में, मेरा मानना ​​है कि मनाया घटना असाधारण रूप से बड़े कोर डंपों की लंबी पीढ़ी के कारण थी।

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

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

वर्तमान में, मैं इस बात के बारे में अनिश्चित हूं कि अपवादों को छोड़ने के लिए केवल अपवाद को पकड़ने का कोई बड़ा फायदा या नुकसान है या नहीं main()

छोटा सा लाभ जिसके बारे में मैं सोच सकता हूं main()कि अतीत को बुलबुला बनाने के लिए अपवाद की अनुमति है कि यह std::exception::what()टर्मिनल पर मुद्रित होने का कारण बनता है (कम से कम लिनक्स पर जीसीसी संकलित कार्यक्रमों के साथ)। दूसरी ओर, इसके std::exceptionपरिणामस्वरूप प्राप्त होने वाले सभी अपवादों को पकड़ने और परिणाम std::exception::what()को प्रिंट करने के बजाय प्राप्त करने के लिए यह तुच्छ है और यदि किसी अपवाद से एक संदेश प्रिंट करना वांछनीय है जो std::exceptionतब से नहीं निकलता है तो प्रिंट करने के लिए निकलने से पहले इसे पकड़ा जाना चाहिए main()संदेश।

मामूली नुकसान मैं अतीत को बुलबुला करने के अपवादों की अनुमति के लिए सोच सकता हूं main()कि अवांछित कोर डंप उत्पन्न हो सकते हैं। स्मृति की एक बड़ी मात्रा का उपयोग करने वाली प्रक्रिया के लिए यह काफी उपद्रव हो सकता है और एक कार्यक्रम से कोर डंपिंग व्यवहार को नियंत्रित करने के लिए ओएस-विशिष्ट फ़ंक्शन कॉल की आवश्यकता होती है। दूसरी ओर, यदि कोई कोर डंप और निकास वांछित है, तो इसे कॉल करके किसी भी समय प्राप्त किया जा सकता है std::abort()और कोर डंप के बिना किसी निकास को कॉल करके किसी भी समय प्राप्त किया जा सकता है std::exit()

वास्तविक रूप से, मुझे नहीं लगता कि मैंने what(): ...दुर्घटनाग्रस्त होने पर व्यापक रूप से वितरित कार्यक्रम द्वारा मुद्रित डिफ़ॉल्ट संदेश देखा है ।

क्या, यदि कोई हो, तो सी ++ अपवादों को अतीत में बुलबुले के लिए अनुमति देने के खिलाफ या मजबूत तर्क हैं main()?

संपादित करें: इस साइट पर बहुत सारे सामान्य अपवाद हैंडलिंग प्रश्न हैं। मेरा प्रश्न विशेष रूप से C ++ अपवादों के बारे में है जिन्हें संभाला नहीं जा सकता है और इसे सभी तरह से बना दिया है main()- शायद एक त्रुटि संदेश मुद्रित किया जा सकता है, लेकिन यह एक तुरंत रोक त्रुटि दिखा रहा है।




@gnat मेरा प्रश्न थोड़ा अधिक विशिष्ट है। यह C ++ अपवादों के बारे में है, जिन्हें किसी भी परिस्थिति में किसी भी प्रोग्रामिंग भाषा में अपवाद हैंडलिंग के बजाय नियंत्रित नहीं किया जा सकता है।
प्रिक्सोलिटिक

बहु-थ्रेडेड प्रोग्राम्स के लिए, चीजें अधिक जटिल या अधिक विदेशी (wrt अपवाद) हो सकती हैं
Basile Starynkevitch

1
एरियन 5 के लिए सॉफ्टवेयर लोग निश्चित रूप से चाहते हैं कि उन्होंने पहले लॉन्च के दौरान सभी अपवादों को पकड़ा था ...
एरिक टॉवर्स

जवाबों:


25

अपवादों को मुख्य रूप से जाने देने में एक समस्या यह है कि प्रोग्राम एक कॉल के साथ समाप्त हो जाएगा std::terminateजिसमें डिफ़ॉल्ट व्यवहार कॉल करना है std::abort। यह केवल कार्यान्वयन को परिभाषित करता है यदि स्टैक अनइंडिंग को कॉल terminateकरने से पहले किया जाता है तो आपका प्रोग्राम एक भी विध्वंसक को कॉल किए बिना समाप्त हो सकता है! यदि आपके पास कुछ संसाधन हैं जिन्हें वास्तव में एक विध्वंसक कॉल द्वारा बहाल करने की आवश्यकता है, तो आप अचार में हैं ...


12
यदि आपके पास कुछ संसाधन हैं जिन्हें वास्तव में एक विध्वंसक कॉल द्वारा बहाल किए जाने की आवश्यकता है, तो आप अचार में हैं ... => यह देखते हुए कि (दुर्भाग्य से) C ++ काफी क्रैश-प्रोन है, और यह उल्लेख किए बिना कि ओएस मारने का फैसला कर सकता है किसी भी समय आपका कार्यक्रम (उदाहरण के लिए यूनिक्स में OOM किलर), आपके प्रोग्राम (और उसके वातावरण) को क्रैश का समर्थन करने के लिए अनुरूप होना चाहिए।
मथिउ एम।

@MatthieuM। क्या आप कह रहे हैं कि विध्वंसक संसाधन सफाई के लिए एक अच्छी जगह नहीं है जो दुर्घटना के दौरान भी होनी चाहिए?
प्रिक्सॉलिटिक

6
@Praxeolitic: मैं कह रहा हूं कि सभी क्रैश स्टैक को नहीं खोलते हैं, उदाहरण के लिए std::abortऔर इस प्रकार विफल दावे भी नहीं करते हैं। यह भी ध्यान देने योग्य है कि आधुनिक ओएस पर, ओएस खुद बहुत सारे संसाधनों (मेमोरी, फ़ाइल हैंडल, ...) को साफ कर देगा जो प्रक्रिया आईडी से बंधे हैं। अंत में, मैं "डिफेंस इन डेप्थ" पर भी इशारा कर रहा था: यह उम्मीद करना अविश्वसनीय है कि अन्य सभी प्रक्रियाएं बग-प्रूफ हैं और वे हमेशा अपने द्वारा अधिग्रहित संसाधनों (सत्रों, अच्छी तरह से लिखने की फाइलों को समाप्त करना ...) को जारी करना होगा। यह ...
मैथ्यू एम।

3
@Praxeolitic नहीं, पावर विफलता के दौरान आपके सॉफ़्टवेयर को दूषित डेटा नहीं चाहिए । और अगर आप इसे प्रबंधित कर सकते हैं, तो आप एक अनचाहे अपवाद के बाद भ्रष्ट डेटा न करने का प्रबंधन भी कर सकते हैं।
user253751

1
@Praxeolitic: वास्तव में, यह मौजूद है। आप WM_POWERBROADCASTसंदेश के लिए सुनना चाहते हैं । यह केवल तभी काम करता है जब आपका कंप्यूटर बैटरी से संचालित हो (यदि आप लैपटॉप या यूपीएस का उपयोग कर रहे हैं)।
ब्रायन

28

अपवादों को न होने देने का मुख्य कारण यह mainहै कि अन्यथा आप यह नियंत्रित करने की पूरी संभावना खो देते हैं कि समस्या आपके उपयोगकर्ताओं को कैसे दिखाई देती है।

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

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


क्या आप सुनिश्चित हैं कि सी ++ अपवाद का डिफ़ॉल्ट व्यवहार main() ओएस के साथ बहुत कुछ करता है? OS को C ++ का कुछ भी पता नहीं हो सकता है। मेरा अनुमान था कि यह कोड संकलक द्वारा प्रोग्राम में कहीं पर निर्धारित किया गया है।
प्रिक्सोलिटिक

5
@Praxeolitic: यह अधिक है कि ओएस कन्वेंशन सेट करता है और कंपाइलर उन सम्मेलनों को पूरा करने के लिए कोड उत्पन्न करता है जब कोई प्रोग्राम अनपेक्षित रूप से समाप्त हो जाता है। लब्बोलुआब यह है कि जब भी संभव हो अप्रत्याशित कार्यक्रम समाप्ति से बचा जाना चाहिए।
बार्ट वैन इनगेन शेनॉउ

आप केवल St + C ++ के दायरे में नियंत्रण को ढीला करते हैं। ऐसे "क्रैश" को संभालने के लिए एक कार्यान्वयन विशिष्ट तरीका उपलब्ध होना चाहिए। C ++ आमतौर पर वैक्यूम में नहीं चलती है।
मार्टिन बा

उस-इन-फेस एरर डायलॉग को रजिस्ट्री में ऑन / ऑफ के लिए कॉन्फ़िगर किया जा सकता है, जो इसके लायक है - लेकिन आपको ऐसा करने के लिए रजिस्ट्री पर नियंत्रण की आवश्यकता होगी - और अधिकांश प्रोग्राम कियोस्क मोड में नहीं चल रहे हैं (पर लिया गया है) ओएस)।
पेरीसी

11

TL; DR : विनिर्देश क्या कहता है?


एक तकनीकी चक्कर ...

जब एक अपवाद फेंक दिया जाता है और कोई हैंडलर इसके लिए तैयार नहीं होता है:

  • यह कार्यान्वित किया गया है कि स्टैक निराधार है या नहीं
  • std::terminate कहा जाता है, जो डिफ़ॉल्ट रूप से गर्भपात करता है
  • आपके पर्यावरण सेटअप के आधार पर, गर्भपात एक दुर्घटना रिपोर्ट को पीछे छोड़ सकता है या नहीं छोड़ सकता है

उत्तरार्द्ध बहुत ही असंगत बग के लिए उपयोगी हो सकता है (क्योंकि उन्हें पुन: प्रस्तुत करना एक समय बर्बाद करने वाली प्रक्रिया है)।


सभी अपवादों को पकड़ना है या नहीं, आखिरकार, विनिर्देश की बात है:

  • क्या यह निर्दिष्ट है कि उपयोगकर्ता त्रुटियों की रिपोर्ट कैसे करें? (अमान्य मूल्य, ...)
  • क्या यह निर्दिष्ट है कि कार्यात्मक त्रुटियों की रिपोर्ट कैसे करें? (लापता लक्ष्य निर्देशिका, ...)
  • क्या यह निर्दिष्ट है कि तकनीकी त्रुटियों की रिपोर्ट कैसे करें? (जोर से फायरिंग, ...)

किसी भी उत्पादन कार्यक्रम के लिए, इसे निर्दिष्ट किया जाना चाहिए, और आपको विनिर्देश का पालन करना चाहिए (और शायद यह तर्क दिया जाए कि इसे बदल दिया जाए)।

केवल तकनीकी लोगों (आप, आपके साथियों) द्वारा उपयोग किए जाने वाले कार्यक्रमों को एक साथ फेंकने के लिए, या तो ठीक है। मैं आपको अपनी आवश्यकताओं के आधार पर रिपोर्ट प्राप्त करने या न करने के लिए इसे क्रैश और सेटअप करने देने की सलाह देता हूं।


1
यह। निर्णायक कारक wrt। मूल रूप से C ++ के दायरे से बाहर हैं।
मार्टिन बा

4

एक अपवाद जो आप पकड़ते हैं, आपको एक अच्छा त्रुटि संदेश प्रिंट करने का अवसर देता है या यहां तक ​​कि त्रुटि से उबरने का प्रयास करता है (संभवतः केवल एप्लिकेशन को फिर से लॉन्च करके)।

हालाँकि, C ++ में कोई अपवाद प्रोग्राम स्थिति के बारे में जानकारी नहीं रखता है जब उसे फेंक दिया गया था। यदि आप इसे पकड़ लेते हैं, तो ऐसी सभी स्थिति को भुला दिया जाता है, जबकि यदि आप प्रोग्राम को क्रैश होने देते हैं, तो राज्य आमतौर पर अभी भी है और प्रोग्राम डंप से पढ़ा जा सकता है, जिससे डिबग करना आसान हो जाता है।

तो यह एक व्यापार बंद है।


4

जिस क्षण आप जानते हैं कि आपको गर्भपात करना है, आगे बढ़ें और std::terminateकिसी और क्षति को रोकने के लिए पहले से ही कॉल करें ।

यदि आप जानते हैं कि आप सुरक्षित रूप से हवा कर सकते हैं, तो इसके बजाय ऐसा करें। याद रखें कि जब कोई अपवाद कभी पकड़ा नहीं जाता है तो स्टैक-अनइंडिंग की गारंटी नहीं होती है, इसलिए कैच और रीथ्रो करें।

यदि आप सुरक्षित रूप से त्रुटि की रिपोर्ट कर सकते हैं / लॉग कर सकते हैं तो सिस्टम इसे अपने दम पर कर देगा, आगे बढ़ें।
लेकिन वास्तव में सुनिश्चित करें कि ऐसा करते समय अनजाने में मामले ज्यादा खराब न हों।

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


1

सुंदर ढंग से क्रैश करना ज्यादातर समय एक अच्छी बात है - लेकिन व्यापार बंद हैं। कभी-कभी दुर्घटनाग्रस्त होना अच्छी बात है। मुझे यह उल्लेख करना चाहिए कि मैं बहुत बड़े पैमाने पर डिबगिंग के बारे में सोच रहा हूं। एक साधारण कार्यक्रम के लिए - हालाँकि यह अभी भी उपयोगी हो सकता है, यह कहीं भी मददगार नहीं है क्योंकि यह एक बहुत ही जटिल कार्यक्रम (या कई जटिल कार्यक्रमों के साथ बातचीत करने वाला) है।

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

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

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

यदि आप रुचि रखते हैं तो आप यहां स्थानीय क्रैश डंप के बारे में अधिक पढ़ सकते हैं: उपयोगकर्ता-मोड डंप एकत्रित करना


-6

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

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

क्रैशिंग सख्ती से शौकिया घंटे है।


8
तो, बेहतर दिखावा सब कुछ सही काम कर रहा है और इसके बजाय गिबरिश के साथ सभी स्थायी भंडारण को अधिलेखित करता है?
डेडुप्लिकेटर

1
@Deduplicator: नहीं: आप हमेशा अपवाद को पकड़ सकते हैं और संभाल सकते हैं।
जियोर्जियो

5
यदि आप जानते हैं कि इसे कैसे संभालना है, तो आप उठने से पहले शायद इसे संभाल लेंगे main। यदि आप नहीं जानते कि इसे कैसे संभालना है, तो आप जो दिखावा कर रहे हैं वह जाहिर तौर पर एक बहुत ही भयानक बग है।
Deduplicator

8
लेकिन दुर्घटनाग्रस्त होना पूरी तरह से गैर-लाभकारी और अस्वीकार्य है > बेकार सुविधाओं पर काम करने में समय व्यतीत करना अव्यावहारिक है: क्रैश केवल तभी मायने रखता है यदि यह अंतिम उपयोगकर्ता के लिए मायने रखता है, यदि यह नहीं है, तो इसे क्रैश होने दें (और एक दुर्घटना की रिपोर्ट दें, मेमोरी डंप के साथ) अधिक किफायती है।
मथिउ एम।

Matthieu M. अगर यह वास्तव में आपको एक त्रुटि लॉग करने, किसी भी खुली फ़ाइलों को सहेजने, और स्क्रीन पर एक मैसेज मैसेज पेंट करने के लिए बहुत प्रयास करता है, तो मुझे नहीं पता कि क्या कहना है। अगर आपको लगता है कि यह शालीनतापूर्वक असफल होना बेकार है, तो आपको संभवतः अपने कोड के लिए तकनीकी सहायता करने वाले से बात करनी चाहिए।
रोजर हिल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.