अपवाद विनिर्देश क्यों खराब हैं?


50

कुछ 10 साल पहले स्कूल में वापस, वे आपको अपवाद निर्दिष्टताओं का उपयोग करना सिखा रहे थे। चूँकि मेरी पृष्ठभूमि उनमें से एक है, जो टॉरवेल्ड सी प्रोग्रामर हैं, जो ज़बरदस्ती सी ++ से बचते हैं, जब तक कि मुझे मजबूर नहीं किया जाता है, मैं केवल सी ++ में छिटपुट रूप से समाप्त होता हूं, और जब मैं अभी भी अपवाद निर्दिष्टकों का उपयोग करता हूं, तो वही है जो मुझे सिखाया गया था।

हालाँकि, C ++ प्रोग्रामर्स के बहुमत अपवाद विनिर्देशक पर आधारित प्रतीत होते हैं। मैंने विभिन्न C ++ गुरुओं की बहस और तर्कों को इन जैसे पढ़ा है । जहां तक ​​मैं इसे समझता हूं, यह तीन चीजों को उबालता है:

  1. अपवाद विनिर्देशक एक प्रकार की प्रणाली का उपयोग करते हैं जो बाकी भाषा ("छाया प्रकार प्रणाली") के साथ असंगत है।
  2. यदि अपवाद के साथ आपका फ़ंक्शन निर्दिष्ट करता है तो आपके द्वारा निर्दिष्ट किए गए के अलावा और कुछ भी नहीं फेंकता है, प्रोग्राम खराब, अप्रत्याशित तरीके से समाप्त हो जाएगा।
  3. आगामी C ++ मानक में अपवाद विनिर्देशक हटा दिए जाएंगे।

क्या मुझे यहाँ कुछ याद आ रहा है या ये सभी कारण हैं?

मेरी अपनी राय:

1 के बारे में): तो क्या। C ++ संभवतः अब तक की सबसे असंगत प्रोग्रामिंग भाषा है, जिसे सिंटेक्स-वार बनाया गया है। हमारे पास मैक्रो, गोटो / लेबल्स, अपरिभाषित- / अनिर्दिष्ट- / अनिर्दिष्ट- / कार्यान्वयन-परिभाषित व्यवहार, खराब-परिभाषित पूर्णांक प्रकार, सभी निहित प्रकार के प्रचार नियम, विशेष-केस कीवर्ड जैसे मित्र, ऑटो , रजिस्टर, स्पष्ट ... और इसी तरह। कोई शायद C / C ++ में सभी अजीबता की कई मोटी किताबें लिख सकता है। तो लोग इस विशेष असंगति के खिलाफ प्रतिक्रिया क्यों कर रहे हैं, जो कि भाषा की कई अन्य खतरनाक विशेषताओं की तुलना में एक मामूली दोष है?

2 के बारे में): क्या मेरी अपनी जिम्मेदारी नहीं है? कई अन्य तरीके हैं जिनसे मैं C ++ में एक घातक बग लिख सकता हूं, यह विशेष मामला किसी भी बदतर क्यों है? लिखने throw(int)और फिर क्रैश_टी को फेंकने के बजाय, मैं यह भी दावा कर सकता हूं कि मेरा फ़ंक्शन int के लिए एक संकेतक लौटाता है, फिर एक जंगली, स्पष्ट टाइपकास्ट बनाएं और एक Crash_t को सूचक लौटाएं। C / C ++ की भावना हमेशा प्रोग्रामर को अधिकांश जिम्मेदारी छोड़ने के लिए होती है।

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

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

void func() throw(Egg_t);

तथा

void func(); // This function throws an Egg_t

मुझे लगता है कि एक बड़ा मौका है कि कॉल करने वाला दूसरे मामले में ट्राई-कैच को लागू करने की उपेक्षा करता है / भूल जाता है, पहले मामले में कम।

जैसा कि मैं इसे समझता हूं, अगर इन दोनों रूपों में से एक या तो अचानक दूसरे प्रकार के अपवाद को फेंकने का फैसला करता है, तो कार्यक्रम क्रैश हो जाएगा। पहले मामले में क्योंकि इसे दूसरे अपवाद को फेंकने की अनुमति नहीं है, दूसरे मामले में क्योंकि किसी को भी यह उम्मीद नहीं थी कि वह स्पैनिशइन्क्वायरी_टी फेंकेगा और इसलिए यह अभिव्यक्ति नहीं पकड़ी जाएगी जहां इसे होना चाहिए था।

उत्तरार्द्ध के मामले में, कार्यक्रम के उच्चतम स्तर पर कुछ अंतिम रिज़ॉर्ट कैच (...) होना वास्तव में किसी प्रोग्राम क्रैश से बेहतर नहीं लगता है: "अरे, आपके कार्यक्रम में कहीं कुछ अजीब, बिना किसी अपवाद के फेंक दिया गया है। । "। एक बार जब आप उस प्रोग्राम को पुनर्प्राप्त नहीं कर सकते हैं, जहां से अपवाद को फेंक दिया गया था, तो केवल एक चीज जो आप कर सकते हैं वह है प्रोग्राम से बाहर निकलना।

और उपयोगकर्ता के दृष्टिकोण से, वे कम परवाह नहीं कर सकते थे यदि उन्हें ओएस से एक दुष्ट संदेश बॉक्स मिलता है जो कह रहा है "प्रोग्राम समाप्त हो गया। पता 0x12345 पर Blablabla" या आपके प्रोग्राम से एक दुष्ट संदेश बॉक्स "अनहैंड अपवाद": myassass। func.something "। बग अभी भी है।


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


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

10
@ मर्टिन: क्योंकि मैं यह बताना चाहता हूं कि मैं दोनों पक्षपाती हूं और सभी विवरणों के साथ तारीख तक नहीं, लेकिन यह भी कि मैं भोली और / या अभी तक बर्बाद आँखों के साथ भाषा का संबंध नहीं करता हूं। लेकिन यह भी कि सी और सी ++ पहले से ही अविश्वसनीय रूप से त्रुटिपूर्ण भाषाएं हैं, इसलिए एक या अधिक दोष वास्तव में मायने नहीं रखते हैं। पोस्ट को संपादित करने से पहले वास्तव में बहुत बुरा था :) अपवाद अपवादकर्ताओं के खिलाफ तर्क भी काफी व्यक्तिपरक हैं और इसलिए उनके बारे में चर्चा करना कठिन है बिना व्यक्तिपरक हो।

SpanishInquisition_t! प्रफुल्लित! मैं व्यक्तिगत रूप से अपवादों को फेंकने के लिए स्टैक फ्रेम पॉइंटर के उपयोग से प्रभावित था और ऐसा लगता है कि यह कोड को बहुत अधिक क्लीनर बना सकता है। हालाँकि, मैंने कभी अपवाद के साथ वास्तव में कोड नहीं लिखा। मुझे पुराने जमाने का कहो, लेकिन वापसी के मूल्य मेरे लिए ठीक काम करते हैं।
शाहबाज

@ शहाबज़ जैसा कि एक पंक्ति के बीच में पढ़ा जा सकता है, मैं काफी पुराने जमाने का हूँ, लेकिन फिर भी मैंने कभी यह सवाल नहीं किया कि क्या अपवाद स्वयं अच्छे हैं या बुरे।

2
थ्रो का भूतकाल फेंक दिया जाता है , फेंका नहीं जाता । यह एक मजबूत क्रिया है।
TRIG

जवाबों:


48

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

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


2
लेकिन रन-टाइम चेक अपवाद के रूप में अपवाद की गलती नहीं है, बल्कि मानक के किसी भी हिस्से के बजाय जो बताता है कि गलत प्रकार फेंकने पर समाप्ति होनी चाहिए। क्या यह इस गतिशील जाँच की ओर ले जाने वाली आवश्यकता को दूर करने के लिए स्मार्ट नहीं होगा और संकलक द्वारा हर चीज का मूल्यांकन किया जाएगा? ऐसा लगता है कि आरटीटीआई यहां का सच्चा अपराधी है, या ...?

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

3
@ ऑर्ब्जवर: मुझे लगता है कि स्टैटिक चेक काफी संभव हैं - अपवाद स्पेक एक फंक्शन के स्पेसिफिकेशन (जैसे रिटर्न वैल्यू) का हिस्सा होगा और फंक्शन पॉइंटर्स, वर्चुअल ओवरराइड्स आदि के लिए कम्पैटिबल स्पेक्स होने चाहिए। मुख्य आपत्ति यह होगी कि यह एक सर्व-या-कुछ भी विशेषता नहीं है - स्थैतिक अपवाद चश्मा वाले कार्य विरासत कार्यों को नहीं कह सकते। (C फ़ंक्शन को कॉल करना ठीक होगा, क्योंकि वे कुछ भी फेंक नहीं सकते हैं)।
माइक सेमोर

2
@ लुंडिन: अपवाद चश्मा हटाया नहीं गया है, बस हटा दिया गया है। विरासत कोड जो उनका उपयोग करता है वह अभी भी मान्य होगा।
माइक सेमोर

1
@ लुंडिन: अपवाद के चश्मे के साथ C ++ के पुराने संस्करण पूरी तरह से संगत हैं। यदि कोड पहले मान्य था, तो वे न तो संकलन करने और न ही अप्रत्याशित रूप से चलाने में विफल होंगे।
19-16 बजे डेडएमजी

18

एक कारण कोई भी उनका उपयोग नहीं करता है क्योंकि आपकी प्राथमिक धारणा गलत है:

"सबसे स्पष्ट [लाभ] यह है कि यदि आपका फ़ंक्शन आपके द्वारा निर्दिष्ट के अलावा किसी भी प्रकार को स्पष्ट रूप से फेंकने की कोशिश करता है, तो संकलक आपको एक त्रुटि देगा।"

struct foo {};
struct bar {};

struct test
{
    void baz() throw(foo)
    {
        throw bar();
    }
};

int main()
{
    test x;
    try { x.baz(); } catch(bar &b) {}
}

यह कार्यक्रम बिना किसी त्रुटि या चेतावनी के संकलित करता है ।

इसके अलावा, भले ही अपवाद पकड़ा गया हो , कार्यक्रम अभी भी समाप्त होता है।


संपादित करें: अपने प्रश्न के एक बिंदु का उत्तर देने के लिए, कैच (...) (या बेहतर, कैच (std :: exeption &) या अन्य बेस क्लास, और फिर कैच (...)) उपयोगी है, भले ही आप न करें जानते हैं कि क्या गलत हुआ।

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


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

कठिन भाग्य। Embarcadero / Borland इसके लिए चेतावनी देता है: "फेंक अपवाद अपवाद का उल्लंघन करता है"। जाहिरा तौर पर जीसीसी नहीं करता है। कोई कारण नहीं है कि वे एक चेतावनी को लागू नहीं कर सके। और इसी तरह, एक स्थैतिक विश्लेषण उपकरण इस बग को आसानी से खोज सकता है।

14
@ लुंडिन: कृपया गलत सूचनाओं पर बहस करना और दोहराना शुरू न करें। आपका प्रश्न पहले से ही एक शेख़ी के बारे में कुछ था, और झूठी बातों का दावा करने से मदद नहीं मिलती है। यदि ऐसा होता है तो एक स्थैतिक विश्लेषण उपकरण नहीं मिल सकता है; ऐसा करने में हॉल्टिंग समस्या को हल करना शामिल है। इसके अलावा, इसे पूरे कार्यक्रम का विश्लेषण करने की आवश्यकता होगी, और बहुत बार पूरे स्रोत उपलब्ध नहीं है।
डेविड थॉर्नले

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

1
@ लुंडिन एक अच्छा सवाल। इसका उत्तर यह है कि सामान्य तौर पर, आप यह नहीं जानते हैं कि आप जिन कार्यों को बुला रहे हैं, वे अपवादों को फेंक देंगे, इसलिए सुरक्षित धारणा यह है कि वे सभी करते हैं। इन्हें पकड़ना एक सवाल है, जिसका मैंने स्टैकओवरफ्लो . com/ questions/4025667/… में जवाब दिया । विशेष रूप से प्राकृतिक मॉड्यूल सीमाओं में घटना संचालकों। जेनेरिक विंडो / इवेंट सिस्टम (जैसे) में भागने के अपवादों को दंडित किया जा रहा है। हैंडलर को सभी को पकड़ना चाहिए अगर कार्यक्रम को वहां जीवित रहना है।
काज ड्रैगन

17

एंडर्स हेजलबर्ग के साथ यह साक्षात्कार काफी प्रसिद्ध है। इसमें, वह बताता है कि C # डिज़ाइन टीम ने पहले स्थान पर जाँच अपवादों को क्यों छोड़ दिया। संक्षेप में, दो प्रमुख कारण हैं: संस्करणता और मापनीयता।

मुझे पता है कि ओपी सी ++ पर ध्यान केंद्रित कर रहा है, जबकि हेजलबर्ग सी # पर चर्चा कर रहे हैं, लेकिन हेजलबर्ग जो बिंदु बनाते हैं वह पूरी तरह से सी ++ पर भी लागू होते हैं।


5
"हेजेलबर्ग जो अंक बनाता है वह पूरी तरह से C ++ पर भी लागू होता है" .. गलत! जावा में लागू किए गए अपवादों की जाँच की जाती है ताकि कॉल करने वाले को उनसे निपटने के लिए बाध्य किया जा सके (और / या कॉल करने वाले के कॉल करने वाले आदि)। C ++ में अपवाद चश्मा (जबकि बहुत कमजोर और बेकार) केवल एक ही "फ़ंक्शन-कॉल-सीमा" पर लागू होता है और चेक किए गए अपवादों की तरह "कॉल स्टैक को प्रचारित नहीं " करते हैं।
मार्टिन बा

3
@ मर्टिन: मैं सी ++ में अपवाद चश्मा के व्यवहार के बारे में आपसे सहमत हूं। लेकिन मेरा मुहावरा है कि आप "हेजलसबर्ग बनाता है कि अंक पूरी तरह से C ++ के लिए भी लागू होते हैं" को संदर्भित करता है, ठीक है, हेजल्सबर्ग बनाता है, बजाय C ++ चश्मे से। दूसरे शब्दों में, मैं यहां अपवाद प्रसार के बजाय कार्यक्रम की संस्करणक्षमता और मापनीयता के बारे में बात कर रहा हूं।
सीजरगॉन

3
मैं हेजलबर्ग से बहुत जल्दी असहमत हो गया: "मुझे चिन्हित अपवादों के बारे में जो चिंता है, वे प्रोग्रामर पर लगे हथकंडे हैं। आप प्रोग्रामर को नए APIs उठाते हुए देखते हैं, जिसमें ये सभी थ्रो क्लॉज होते हैं, और फिर आप देखते हैं कि उनका कोड प्राप्त हो जाता है, और आपको एहसास होता है। चेक किए गए अपवाद उन्हें कोई मदद नहीं कर रहे हैं। यह इन तानाशाह एपीआई डिजाइनरों की तरह है जो आपको बता रहे हैं कि आप अपने अपवाद को कैसे संभाल सकते हैं। " --- अपवादों की जाँच की जा रही है या नहीं, आपको अभी भी एपीआई द्वारा आपके द्वारा बुलाए गए अपवादों को संभालना है। जाँच किए गए अपवाद केवल स्पष्ट करते हैं।
मात्रा_देव

5
@quant_dev: नहीं, आपको उस API द्वारा फेंके गए अपवाद को संभालने की आवश्यकता नहीं है जिसे आप कॉल कर रहे हैं। एक पूरी तरह से वैध विकल्प अपवादों को संभालना नहीं है और उन्हें अपने कॉलर को संभालने के लिए कॉल स्टैक को बंद करने दें।
सेसरगॉन

4
@ केसरगॉन अपवादों को नहीं संभालना भी एक विकल्प है कि उन्हें कैसे संभालना है।
क्वांट_देव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.