2011-09-01 12 views
37

new सीखने के बाद मैंने कुछ शोध किया, malloc() के विपरीत, जिसका उपयोग मैं किया जाता हूं, असफल आवंटन के लिए NULL वापस नहीं करता है, और पाया कि दो अलग-अलग तरीके हैं यह जांचने के लिए कि क्या नया सफल हुआ या नहीं। उन दो तरीके हैं:नया (std :: nothrow) बनाम एक कोशिश/पकड़ ब्लॉक

try 
{ 
    ptr = new int[1024]; 
} 
catch(std::bad_alloc& exc) 
{ 
    assert(); 
}; 

और

ptr = new (std::nothrow) int[1024]; 
if(ptr == NULL) 
    assert(); 

मेरा मानना ​​है कि दो तरह से एक ही लक्ष्य को पूरा, (! मुझे ठीक कर लें मैं निश्चित रूप से गलत हूँ), इसलिए मेरे सवाल यह है:

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

+2

अपवादों का उपयोग करें। वे आपके कोड को अधिक सार्थक, स्थानीय, रखरखाव और स्केलेबल बनाते हैं। –

+3

केवल पठनीयता के संबंध में, निश्चित रूप से अपवाद हैंडलिंग के बिना एक। प्रदर्शन के संबंध में, शायद 'नोट्रो' भी हो सकता है। लेकिन मुझे यकीन है कि अतिवादियों का तर्क होगा। लेकिन अगर आप केवल एक सरल दावा विफलता चाहते हैं, तो आप फेंकने वाले संस्करण का भी उपयोग कर सकते हैं और अपवाद हैंडलर को छोड़ सकते हैं;) –

+4

उस कोड का क्या मतलब है? आप एक विशिष्ट, सार्थक अपवाद को पकड़ रहे हैं और फिर 'assert() 'के माध्यम से एक अर्थहीन बना रहे हैं ... – Blindy

उत्तर

47

विचार करें कि आप क्या कर रहे हैं। आप स्मृति आवंटित कर रहे हैं। और अगर किसी कारण से स्मृति आवंटन काम नहीं कर सकता है, तो आप assert। यदि आप std::bad_alloc को main पर प्रचारित करते हैं तो बस इतना ही कम होगा कि क्या होगा। रिलीज बिल्ड में, जहां assert नो-ऑप है, जब आपका मेमोरी एक्सेस करने का प्रयास करता है तो आपका प्रोग्राम क्रैश हो जाएगा। तो यह अपवाद बबल अप देने जैसा ही है: ऐप को रोकना।

तो अपने आप से एक प्रश्न पूछें: क्या आप वास्तव में पर ध्यान देने की ज़रूरत है कि अगर आप स्मृति से बाहर हो जाते हैं तो क्या होता है? यदि आप जो भी कर रहे हैं, वह जोर दे रहा है, तो अपवाद विधि बेहतर है, क्योंकि यह आपके कोड को यादृच्छिक assert एस के साथ अव्यवस्थित नहीं करता है। आप बस अपवाद को main पर गिरने दें।

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

+3

यह एक बहुत ही भरोसेमंद तर्क है, मुझे पता नहीं था कि कैच ब्लॉक खोजने के लिए अपवाद अपवाद कॉल स्टैक पर चढ़ सकते हैं। ... मुझे बहुत सी चीजों के बारे में पता नहीं है अपवाद कर सकते हैं। हो सकता है कि आखिरकार मैं इन सभी वर्षों के बाद इसे सीखूं, आह –

10

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

दूसरी ओर, अपने कार्यक्रम पूरी तरह से से शान से कि स्मृति क्रम में सफलतापूर्वक आवंटित करने के लिए (new के आसपास के क्षेत्र में जरूरी नहीं), में कार्य try-catch का उपयोग को पकड़ने के लिए करने में सक्षम होने की जरूरत है, तो एक अपवाद और बाहर निकलें कार्यक्रम।

+0

मैंने इस पर विचार नहीं किया, मुझे लगता है कि स्थिति के लिए मिश्रण और मिलान करना उस मामले में खराब शैली नहीं होगी। स्पष्ट रूप से उस कारण के लिए दो तरीके मौजूद हैं। धन्यवाद! –

+4

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

6

शुद्ध प्रदर्शन परिप्रेक्ष्य से यह थोड़ा मायने रखता है। अपवाद हैंडलिंग के साथ अंतर्निहित ओवरहेड है, हालांकि यह ओवरहेड आमतौर पर आवेदन पठनीयता और रखरखाव में व्यापार के लायक है। इस प्रकृति की स्मृति आवंटन विफलताओं को आपके आवेदन के 99% मामले में नहीं होना चाहिए, इसलिए यह अक्सर घटित होना चाहिए।

एक प्रदर्शन परिप्रेक्ष्य से आप आम तौर पर इसके अपेक्षाकृत खराब प्रदर्शन के कारण मानक आवंटन से बचना चाहते हैं।

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

+0

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

+0

अपवादों (भाषा आपके लिए करता है) का उपयोग करते समय अभी भी कुछ जुर्माना है, जैसे सेटिंग उचित रूप से ढेर ऊपर, एसईएच प्रसंस्करण, आदि। आम तौर पर मैं उन दोनों के बीच एक मापनीय अंतर होने की अपेक्षा नहीं करता जहां "कुछ भी गलत नहीं होता है।" विफलता के मामले में अपवाद कोड अधिक शामिल होगा, लेकिन यह 'पूर्ण' चेक की आवश्यकता नहीं होने के कारण कोड को साफ़ करता है। हालांकि यह वास्तव में उस बिंदु से व्यक्तिगत वरीयता का मामला है। – Chad

+2

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

-3

new वस्तुओं को बनाने के लिए उपयोग किया जाता है, स्मृति आवंटित नहीं किया जाता है, इसलिए आपका उदाहरण कुछ कृत्रिम है।

ऑब्जेक्ट कन्स्ट्रक्टर आम तौर पर विफल होने पर फेंक देते हैं। विजुअल स्टूडियो में new कार्यान्वयन के माध्यम से कुछ बार से अधिक कदम उठाने के बाद, मुझे विश्वास नहीं है कि कोड में कोई अपवाद है। इसलिए वस्तुओं को बनाते समय अपवादों को देखना आम तौर पर समझ में आता है।

I सोचेंstd::bad_alloc केवल तभी फेंक दिया जाता है जब स्मृति आवंटन भाग विफल हो जाता है। मुझे यकीन नहीं है कि क्या होता है यदि आप std::nothrow से new पास करते हैं लेकिन ऑब्जेक्ट कन्स्ट्रक्टर फेंकता है - मैंने जो दस्तावेज़ पढ़े हैं उनमें अस्पष्टता है।

2 दृष्टिकोणों के बीच प्रदर्शन में अंतर शायद अप्रासंगिक है क्योंकि अधिकांश प्रोसेसर समय ऑब्जेक्ट कन्स्ट्रक्टर में आसानी से खर्च किया जा सकता है या ढेर खोज सकता है।

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

+0

यदि आपके मुख्य ऑब्जेक्ट में सबोबजेक्ट हैं, तो वे खराब आवंटन को फेंक सकते हैं अगर वे स्मृति आवंटित करते हैं ... तो आप निश्चित रूप से यह नहीं जान पाएंगे कि यह मुख्य आवंटन है अनुत्तीर्ण होना। हालांकि, आपको परवाह नहीं है क्योंकि ऑब्जेक्ट वैसे भी प्रयोग योग्य नहीं है और संकलक आंशिक रूप से निर्मित वस्तुओं की आवश्यक सफाई करने का ख्याल रखेगा। ** मैं आपको पहले भाषा सीखने का सुझाव दूंगा ** भ्रामक जवाब देने से पहले। विशेष रूप से, ऑब्जेक्ट्स बनाते समय अपवादों को देखने की आपकी सिफारिश खराब होती है यदि इसका मतलब हर आवंटन के चारों ओर प्रयास/पकड़ना है। – Phil1970

+0

पेशेवर अनुप्रयोगों में इस्तेमाल किए गए किसी भी कोड को लिखने से पहले मैं आपको ** असाधारण सी ++ ** और अन्य समान पुस्तकों को पढ़ने की सिफारिश करता हूं। – Phil1970

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