2008-11-19 15 views
62

के लिए कोई नुक्कड़ जांचने के लिए आवश्यक कुछ दिशानिर्देश क्या हैं?कितना शून्य जांच पर्याप्त है?

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

मैंने "अन्य कोड पर भरोसा नहीं कर सकते" से "कई कार्यक्रमों पर भरोसा नहीं कर सकते" से लेकर कई तर्क सुना है, जब तक कि भाषा मुझे एक गैर-शून्य मूल्य की गारंटी न दे, मैं हमेशा जांच कर रहा हूं। " मैं निश्चित रूप से उन सिद्धांतों में से कई बिंदुओं से सहमत हूं, लेकिन मुझे लगता है कि अत्यधिक नल-जांच अन्य समस्याओं का कारण बनती है जो आम तौर पर उन सिद्धांतों का उल्लंघन करती हैं। क्या दृढ़ शून्य जांच वास्तव में इसके लायक है?

अक्सर, मैंने उच्च गुणवत्ता वाले नहीं, वास्तव में गरीब गुणवत्ता के लिए अत्यधिक शून्य जांच के साथ कोड देखे हैं। अधिकांश कोड नल-चेक पर इतना ध्यान केंद्रित करते हैं कि डेवलपर ने अन्य महत्वपूर्ण गुणों जैसे कि पठनीयता, शुद्धता, या अपवाद हैंडलिंग की दृष्टि खो दी है। विशेष रूप से, मुझे लगता है कि बहुत सारे कोड std :: bad_alloc अपवाद को अनदेखा करते हैं, लेकिन new पर एक नल-चेक करें।

सी ++ में, मैं इसे कुछ हद तक समझता हूं क्योंकि एक शून्य सूचक को अपरिवर्तनीय व्यवहार के अप्रत्याशित व्यवहार के कारण; जावा, सी #, पायथन इत्यादि में शून्य ड्रेफरेंस को अधिक सुन्दर तरीके से संभाला जाता है। क्या मैंने अभी सतर्क नल-जांच के खराब उदाहरण देखे हैं या क्या वास्तव में कुछ ऐसा है?

यह प्रश्न भाषा अज्ञेयवादी होने का इरादा है, हालांकि मैं मुख्य रूप से सी ++, जावा और सी # में रूचि रखता हूं। होने के लिए निम्नलिखित अत्यधिक शामिल लगते हैं कि


अशक्त-चेकिंग के कुछ उदाहरणों में मैंने देखा है:


यह उदाहरण सी ++ कल्पना के रूप में गैर मानक compilers के लिए लेखांकन किया जा रहा है एक असफल नया अपवाद फेंकता है। जब तक आप स्पष्ट रूप से गैर-अनुपालन वाले कंपाइलर्स का समर्थन नहीं कर रहे हैं, तो क्या यह समझ में आता है? क्या यह जावा या सी # (या यहां तक ​​कि सी ++/सीएलआर) जैसी प्रबंधित भाषा में कोई समझ बनाता है?

try { 
    MyObject* obj = new MyObject(); 
    if(obj!=NULL) { 
     //do something 
    } else { 
     //??? most code I see has log-it and move on 
     //or it repeats what's in the exception handler 
    } 
} catch(std::bad_alloc) { 
    //Do something? normally--this code is wrong as it allocates 
    //more memory and will likely fail, such as writing to a log file. 
} 

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

यदि कोई तरीका है, जिसे आप देख सकते हैं और अपडेट कर सकते हैं (या डेवलपर जो चिंतित हो सकता है) में अनुबंध हो सकता है, क्या अभी भी नल की जांच करना आवश्यक है?

//X is non-negative. 
//Returns an object or throws exception. 
MyObject* create(int x) { 
    if(x<0) throw; 
    return new MyObject(); 
} 

try { 
    MyObject* x = create(unknownVar); 
    if(x!=null) { 
     //is this null check really necessary? 
    } 
} catch { 
    //do something 
} 

एक निजी या अन्यथा आंतरिक समारोह के विकास, यह वास्तव में स्पष्ट रूप से एक अशक्त को संभालने के लिए जरूरी है कि जब अनुबंध गैर शून्य मान केवल आवश्यकता होने पर? एक नल-चेक एक जोर देने के लिए बेहतर क्यों होगा?

(जाहिर है, अपने सार्वजनिक एपीआई पर, अशक्त-जांच करता है महत्वपूर्ण के रूप में इसे गलत तरीके से एपीआई का उपयोग करने के लिए अपने उपयोगकर्ताओं पर चिल्लाना असभ्य माना जाता है कर रहे हैं)

//Internal use only--non-public, not part of public API 
//input must be non-null. 
//returns non-negative value, or -1 if failed 
int ParseType(String input) { 
    if(input==null) return -1; 
    //do something magic 
    return value; 
} 

की तुलना में:

//Internal use only--non-public, not part of public API 
//input must be non-null. 
//returns non-negative value 
int ParseType(String input) { 
    assert(input!=null : "Input must be non-null."); 
    //do something magic 
    return value; 
} 
+0

नया कभी वापस नहीं लौटाएगा (जब तक कि आप इसे वैकल्पिक रूप से वैकल्पिक रूप से आवश्यक न हों)। इसलिए किसी नए या किसी भी चीज से जांच करने की आवश्यकता नहीं है जो न्यूल वापस नहीं कर सकता (क्योंकि आंतरिक रूप से यह फेंक रहा है)। –

+1

पुराने सी ++ कंपाइलर्स ने इस संबंध में spec का उल्लंघन किया और अपवाद फेंकने के बजाय एक न्यूल वापस कर दिया। माइक्रोसॉफ्ट बड़े उल्लंघन करने वालों में से एक था, लेकिन केवल एक ही नहीं। http://support.microsoft.com/kb/167733 –

+1

मुझे नहीं लगता कि जोर() आपके चौथे नमूने में उपयुक्त है। एक NullPointerException अधिक उपयुक्त होगा। जोर देने के लिए वैध उपयोग हैं() लेकिन यह उनमें से एक नहीं है। – finnw

उत्तर

17

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

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

इनपुट सत्यापन के विषय पर:

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

सी ++ में, दूसरी तरफ, न्यूल लगभग 2^32 (नए आर्किटेक्चर पर 2^64) में से एक है अमान्य मान जो एक सूचक पैरामीटर ले सकता है, क्योंकि लगभग सभी पते सही प्रकार की वस्तुओं के नहीं हैं । जब तक आपके पास उस प्रकार की सभी ऑब्जेक्ट्स की सूची न हो, तब तक आप अपने इनपुट को "पूरी तरह से मान्य" नहीं कर सकते।

तब प्रश्न बन जाता है, क्या (foo *)(-1) विशेष उपचार प्राप्त करने के लिए पर्याप्त रूप से पर्याप्त सामान्य अमान्य इनपुट नहीं है?

जावा के विपरीत, फ़ील्ड को स्वत: प्रारंभ नहीं किया जाता है, इसलिए एक कचरा अनियमित मूल्य न्यूल के रूप में उतना ही सरल है। लेकिन कभी-कभी सी ++ ऑब्जेक्ट्स में पॉइंटर सदस्य होते हैं जो स्पष्ट रूप से पूर्ण-अंतर्निहित होते हैं, जिसका अर्थ है "मेरे पास अभी तक कोई नहीं है"। यदि आपका कॉलर ऐसा करता है, तो प्रोग्रामिंग त्रुटियों का एक महत्वपूर्ण वर्ग है जिसे एक पूर्ण जांच द्वारा निदान किया जा सकता है। लाइब्रेरी में पेज गलती से डीबग करने के लिए उनके लिए एक अपवाद आसान हो सकता है जिनके पास स्रोत नहीं है। तो अगर आपको कोड ब्लोट नहीं लगता है, तो यह सहायक हो सकता है। लेकिन यह आपका कॉलर है, आपको खुद के बारे में सोचना चाहिए - यह रक्षात्मक कोडिंग नहीं है, क्योंकि यह केवल नुल के खिलाफ 'बचाव' करता है, न कि (foo *) (- 1) के खिलाफ।

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

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

उत्पादन मान्यता के विषय पर:

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

सभी मामलों में:

उपयोग दावे बल्कि "वास्तविक कोड" की तुलना में ठेके जहां संभव जाँच करने के लिए - आपके एप्लिकेशन के काम कर रहा है, तो आप शायद नहीं हर कॉल प्राप्त करने वाला अपने सभी आदानों की जाँच के कोड ब्लोट चाहते हैं, और प्रत्येक कॉलर अपने रिटर्न मूल्यों की जांच करता है।

लेखन कोड के मामले जो सवाल जो अशक्त के लिए जाँच करता है और यह भी अपवाद पकड़ता में कोड के बजाय गैर मानक सी ++ कार्यान्वयन करने के लिए पोर्टेबल है, तो में, मैं शायद इस तरह एक समारोह होगा:

template<typename T> 
static inline void nullcheck(T *ptr) { 
    #if PLATFORM_TRAITS_NEW_RETURNS_NULL 
     if (ptr == NULL) throw std::bad_alloc(); 
    #endif 
} 

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

10

हैं आप कोड और उसके अनुबंध को लिखते हैं, आप इसके अनुबंध के संदर्भ में इसका उपयोग करने के लिए जिम्मेदार हैं और यह सुनिश्चित करना कि अनुबंध सही है। यदि आप कहते हैं "एक गैर-शून्य" x देता है, तो कॉलर को शून्य की जांच नहीं करनी चाहिए। यदि एक शून्य सूचक अपवाद तब उस संदर्भ/सूचक के साथ होता है, तो यह आपका अनुबंध गलत है।

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

+0

वह इस बारे में बात कर रहा है जब आपने कोड या (अनुमानतः) अनुबंध नहीं लिखा था। बिंदु को संबोधित नहीं करता है। – dkretz

+0

मुझे लगता है कि वह सामान्य डेवलपर में "आप" का मतलब है, मुझे विशेष रूप से नहीं ... मुझे लगता है कि दूसरा पैराग्राफ प्रासंगिक है। मैंने कोड नहीं लिखा होगा, लेकिन मैं कुछ मामलों में लेखक से बात कर सकता हूं। –

+0

किसी फ़ंक्शन से लौटाए गए मान की जांच क्यों न करें जो अनुबंध में कहता है कि यह एक पूर्ण वापस नहीं करेगा? अनुबंध दस्तावेज है, समारोह कोड है। वे कम से कम, सी ++ में नहीं हैं, जरूरी रूप से सुसंगत हैं। कोड जरूरी नहीं है। आप बस बग पास करते हैं। जल्दी और अक्सर विफल। –

2

यह व्यापक रूप से ज्ञात है कि प्रक्रिया उन्मुख लोग (सही तरीके से काम करने पर ध्यान केंद्रित करते हैं) और परिणाम उन्मुख लोगों (सही उत्तर प्राप्त करें)। हम में से अधिकांश बीच में कहीं झूठ बोलते हैं। ऐसा लगता है कि आपको प्रक्रिया उन्मुख के लिए एक बाहरी मिला है। ये लोग कहेंगे "जब तक आप चीजों को पूरी तरह से समझ नहीं लेते, तब तक कुछ भी संभव है, इसलिए कुछ भी तैयार करें।" उनके लिए, आप जो देखते हैं वह ठीक से किया जाता है। उनके लिए यदि आप इसे बदलते हैं, तो वे चिंता करेंगे क्योंकि बतख सभी को रेखांकित नहीं किया जाता है।

किसी और के कोड पर काम करते समय, मैं यह सुनिश्चित करने का प्रयास करता हूं कि मुझे दो चीजें पता हैं।
1. क्या प्रोग्रामर इरादा
2. क्यों वे कोड तरह वे

किया प्रकार एक प्रोग्रामर पर निम्नलिखित के लिए लिखा है, हो सकता है यह मदद करता है।

तो "कितना पर्याप्त है" एक सामाजिक प्रश्न के रूप में एक सामाजिक प्रश्न के रूप में समाप्त होता है - इसे मापने के लिए कोई सहमति नहीं है।

(यह मुझे पागल भी चलाता है।)

+0

कुछ भी नहीं करना विज्ञापन मतली आमतौर पर # 1 बहुत कठिन बना देगा। एक उदाहरण में, वास्तविक तर्क की ~ 20 लाइनें और नल-चेक और हैंडलिंग की 100 से अधिक पंक्तियां थीं (यानी इसे लॉग करें)। –

34

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

  1. मुझे लगता है कि अन्य लोगों के संपर्क में आएंगे एक सार्वजनिक एपीआई लिख रहा हूँ, तो मुझे क्या करना होगा सभी संदर्भ मानकों के आधार पर।

  2. यदि मैं अपने आवेदन के लिए एक आंतरिक घटक लिख रहा हूं, तो मुझे शून्य जांच होती है जब मुझे कुछ खास करने की ज़रूरत होती है जब एक शून्य मौजूद होता है, या जब मैं इसे बहुत स्पष्ट करना चाहता हूं। अन्यथा मुझे नल संदर्भ अपवाद प्राप्त करने में कोई फर्क नहीं पड़ता क्योंकि यह भी स्पष्ट है कि क्या हो रहा है।

  3. अन्य लोगों के ढांचे से रिटर्न डेटा के साथ काम करते समय, जब मैं संभव हो तो नल की जांच करता हूं और शून्य वापस लौटने के लिए मान्य होता है। अगर उनका अनुबंध कहता है कि यह नल वापस नहीं आता है, तो मैं चेक नहीं करूँगा।

2

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

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

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

+0

सी ++ के पुराने संस्करण, और आईआईआरसी एम्बेडेड सी ++, मॉलोक के समान तरीके से नए से वापस लौटें। –

+0

अफसोस की बात है, कई सालों से कई मुख्यधारा के कंपाइलर्स इस संबंध में सी ++ स्पेक से विचलित हो गए। AFAIK, सी ++ spec * हमेशा * अपवाद की आवश्यकता है। लगभग सभी प्रमुख सी ++ कंपाइलर्स अब spec के अनुपालन में हैं। –

+0

मैंने "जब आप निर्दिष्ट कर सकते हैं कि आप किस कंपाइलर का उपयोग करते हैं" के बारे में एक नोट जोड़ा। यदि आप कोई एप्लिकेशन लिख रहे हैं और बिल्ड वातावरण निर्दिष्ट कर सकते हैं तो कंपाइलर के पुराने संस्करणों में बग को हल करने का कोई कारण नहीं है। – Aaron

7

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

इसलिए जब यह एक परियोजना है, जहां यह उस तरह इकाई परीक्षण और सामान के साथ समर्थित है के भीतर ठीक है:

internal void DoThis(Something thing) 
{ 
    Debug.Assert(thing != null, "Arg [thing] cannot be null."); 
    //... 
} 
एक विधि आप जो इसे कॉल पर नियंत्रण की जरूरत नहीं है जहां में

, कुछ इस तरह हो सकता है बेहतर:

public void DoThis(Something thing) 
{ 
    if (thing == null) 
    { 
     throw new ArgumentException("Arg [thing] cannot be null."); 
    } 
    //... 
} 
+0

चीज एक सूचक नहीं है इसलिए न्यूल नहीं हो सकता है! –

+2

कोड एक सी # उदाहरण प्रतीत होता है, इसलिए कुछ संभावित रूप से एक शून्य-संदर्भ है। –

+0

हाँ, यह सी # है इसलिए चीज निश्चित रूप से शून्य हो सकती है। – djuth

1

निचले स्तर के कोड को उच्च स्तर कोड से उपयोग की जांच करनी चाहिए। आम तौर पर इसका अर्थ तर्कों की जांच करना है, लेकिन इसका अर्थ यह है कि अपवर्कों से वापसी मूल्यों की जांच करना। उपक्रम तर्कों की जांच की आवश्यकता नहीं है।

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

4

सामान्य रूप से सामान्य जांच बुरा है क्योंकि यह कोड टेस्टेबिलिटी के लिए एक छोटा नकारात्मक टोकन जोड़ता है। हर जगह नल चेक के साथ आप "पास नल" तकनीक का उपयोग नहीं कर सकते हैं और यह यूनिट परीक्षण के दौरान आपको मारा जाएगा। शून्य जांच से विधि के लिए यूनिट परीक्षण होना बेहतर है। http://www.youtube.com/watch?v=wEhu57pih5w&feature=channel

2

पर

चेक बाहर Misko Hevery द्वारा सामान्य रूप में कि इस मुद्दे को और इकाई परीक्षण पर सभ्य प्रस्तुति निजी तौर पर मुझे लगता है कि अशक्त परीक्षण मामलों के महान बहुमत में unnnecessary है। यदि नया असफल रहता है या मॉलोक विफल रहता है तो आपके पास बड़े मुद्दे हैं और पुनर्प्राप्ति का मौका सिर्फ उन मामलों में शून्य है जहां आप मेमोरी चेकर नहीं लिख रहे हैं! इसके अलावा शून्य परीक्षण विकास चरणों में बहुत कुछ छिपाता है क्योंकि "शून्य" खंड अक्सर खाली होते हैं और कुछ भी नहीं करते हैं।

7

यह स्थिति पर निर्भर करता है। मेरा बाकी जवाब सी ++ मानता है।

  • मैं सभी कार्यान्वयन मैं विफलता पर फेंक bad_alloc का उपयोग के बाद से नई की वापसी मूल्य का परीक्षण कभी नहीं। यदि मैं किसी भी कोड में काम कर रहे नए कोड शून्य के लिए विरासत परीक्षण देखता हूं, तो मैं इसे काटता हूं और को किसी भी चीज़ से प्रतिस्थापित नहीं करता हूं।
  • जब तक छोटे दिमागी कोडिंग मानकों इसे प्रतिबंधित नहीं करते हैं, तो मैंने दस्तावेज पूर्व शर्त लगाए हैं। टूटा कोड जो एक प्रकाशित अनुबंध का उल्लंघन करता है तुरंत विफल होने और नाटकीय रूप से विफल होने के लिए।
  • यदि कोई रनटाइम विफलता से उत्पन्न होता है जो कोड टूटा हुआ है, तो मैं फेंक देता हूं।fopen विफलता और malloc विफलता (हालांकि शायद ही कभी कभी भी उन्हें C++ में उपयोग करें) इस श्रेणी में गिर जाएगी।
  • मैं आवंटन विफलता से पुनर्प्राप्त करने का प्रयास नहीं करता हूं। Bad_alloc मुख्य() में पकड़ा गया।
  • यदि शून्य परीक्षण किसी ऑब्जेक्ट के लिए है जो मेरी कक्षा के सहयोगी है, तो मैं इसे संदर्भ के अनुसार कोड लिखता हूं।
  • तो सहयोगी वास्तव में मौजूद नहीं सकता है, मैं Null Object डिजाइन पैटर्न का उपयोग में अच्छी तरह से परिभाषित तरीके विफल एक प्लेसहोल्डर बनाने के लिए।
3

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

यह सब विफल रही आवंटन एक ही कोड मार्ग का अनुसरण करने के लिए क्लीनर होगा:

if(obj==NULL) 
    throw std::bad_alloc(); 
1

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

2

मैं कहूंगा कि यह आपकी भाषा पर थोड़ा निर्भर करता है, लेकिन मैं सी # के साथ रिशेर्पर का उपयोग करता हूं और यह मूल रूप से मुझे यह बताने का तरीका है कि "यह संदर्भ शून्य हो सकता है" जिस स्थिति में मैं एक चेक जोड़ता हूं, अगर यह मुझे बताता है "अगर यह हमेशा सच रहेगा" के लिए "अगर (शून्य! = oMyThing & & ....)" तो मैं इसे सुनो के लिए परीक्षण नहीं करता हूं।

+0

जावा में FindBugz चेतावनी "लापता" और "अनावश्यक" शून्य जांच के मामले में बहुत समान समर्थन प्रदान करता है। –

1

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

यह केवल एनयूएलएल के बारे में नहीं है, यदि संभव हो तो एक समारोह को पूर्व-और बाद की स्थितियों की जांच करनी चाहिए।

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

इसके अलावा, यदि कोई अपवाद मुख्य से बच निकलता है, तो ढेर को घुमाया नहीं जा सकता है, विनाशकों को बिल्कुल चलने से रोकता है (टर्मिनेंट() पर सी ++ मानक देखें)। जो गंभीर हो सकता है। इसलिए Bad_alloc अनचेक छोड़ने से ऐसा लगता है कि यह अधिक खतरनाक हो सकता है।

जोरदार बनाम विफलता के साथ असफल रन टाइम त्रुटि के साथ असफल एक अलग विषय है।

नए() के बाद न्यूल के लिए जांच कर रहा है यदि मानक नया() व्यवहार फेंकने के बजाय नल को वापस करने के लिए परिवर्तित नहीं किया गया है अप्रचलित लगता है।

एक और समस्या है, जो कि मॉलोक ने एक वैध सूचक लौटाया है, फिर भी इसका मतलब यह नहीं है कि आपने स्मृति आवंटित की है और इसका उपयोग कर सकते हैं। लेकिन वो दूसरी कहानी है।

+0

"भले ही मॉलोक ने एक वैध सूचक वापस कर दिया हो, फिर भी इसका मतलब यह नहीं है कि आपने स्मृति आवंटित की है और इसका उपयोग कर सकते हैं" - तकनीकी रूप से, मुझे लगता है कि सी और सी ++ मानकों का कहना है कि इसका मतलब यह है कि, लिनक्स को कोर डंप करना है ("एक दोषी याचिका को पीओ") इस बिंदु पर यह स्मृति को करने में विफल रहता है। –

+0

मुझे लगता है कि यह अलग है। मॉलोक() नई() के विपरीत स्मृति की गारंटी देने में विफल रहता है। फिर जब आप परेशानी में भाग लेते हैं तो आप मारे जाते हैं, और यह भाषा के अलावा काफी सी है। आपकी प्रक्रिया फोर्ट्रान में भी लिखी जा सकती है - लिनक्स कर्नेल को पता नहीं है या परवाह नहीं है। तो यह मानक लागू नहीं है। –

2

चाहे नल की जांच करें या नहीं, परिस्थितियों पर निर्भर करता है।

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

public MyObject MyMethod(object foo) 
{ 
    if (foo == null) 
    { 
    throw new ArgumentNullException("foo"); 
    } 

    // do whatever if foo was non-null 
} 
2

मैं केवल एनयूएलएल की जांच करता हूं जब मुझे पता है कि जब मैं न्यूल देखता हूं तो क्या करना है। "जानें कि क्या करना है" का अर्थ है "क्रैश से बचने के लिए" या "पता है कि दुर्घटना के स्थान के अलावा उपयोगकर्ता को क्या कहना है"। उदाहरण के लिए, यदि malloc() NULL लौटाता है, तो मेरे पास आमतौर पर प्रोग्राम को रद्द करने के अलावा कोई विकल्प नहीं होता है। दूसरी तरफ, अगर फॉपेन() पूर्ण लौटाता है, तो मैं उपयोगकर्ता को उस फ़ाइल नाम को जान सकता हूं जो खुला नहीं हो सकता है और गलत हो सकता है। और यदि पाते हैं() अंत() लौटाता है, तो मुझे आमतौर पर क्रैश होने के बिना कैसे जारी रखना है।

0

सबसे पहले, यह एक अजीब सवाल की तरह लग रहा था: null चेक महान और एक मूल्यवान टूल हैं। यह जांच कर रहा है कि new रिटर्न null निश्चित रूप से मूर्ख है। मैं सिर्फ इस तथ्य को अनदेखा कर रहा हूं कि ऐसी भाषाएं हैं जो इसकी अनुमति देती हैं। मुझे यकीन है कि वैध कारण हैं, लेकिन मुझे नहीं लगता कि मैं उस वास्तविकता में रहना संभाल सकता हूं :) सभी मजाक कर रहे हैं, ऐसा लगता है कि आपको कम से कम यह निर्दिष्ट करना होगा कि newnull वापस आना चाहिए जब वहां नहीं है पर्याप्त स्मृति

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

आवेषण का उपयोग करना वास्तव में एक अच्छा विचार है। विशेष रूप से अगर यह आपको रनटाइम पर बंद करने का विकल्प देता है। इसके अलावा, यह एक और स्पष्ट रूप से संविदात्मक शैली है :)

1

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

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

जगह पर शून्य जांच के साथ एक और समस्या यह है कि कुछ डेवलपर्स वास्तव में वास्तविक समस्या के बारे में सोचने के लिए समय नहीं लेते हैं जब उन्हें NullReferenceException मिलता है। मैंने वास्तव में कुछ डेवलपर्स को देखा है, बस उस कोड के ऊपर एक शून्य जांच जोड़ें जहां NullReferenceException हुआ था। बढ़िया, अपवाद अब नहीं होता है! हुर्रे! हम अभी घर जा सकते हैं! उम्म ... कैसे बकवास 'आप नहीं कर सकते हैं और आप चेहरे पर एक कोहनी लायक हैं'? असली बग अब अपवाद का कारण नहीं बन सकता है, लेकिन अब आपके पास शायद गायब या दोषपूर्ण व्यवहार है ... और कोई अपवाद नहीं! जो भी अधिक दर्दनाक है और डीबग करने के लिए और भी अधिक समय लगता है।

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