क्या NULL पॉइंटर को हटाना सुरक्षित है?


299

क्या NULL पॉइंटर को हटाना सुरक्षित है?

और क्या यह एक अच्छी कोडिंग शैली है?


21
एक कॉल के बिना C ++ प्रोग्राम लिखने के लिए अच्छा अभ्यास है delete। इसकी जगह RAII का इस्तेमाल करें । अर्थात्, std::vector<T> v(100);इसके बजाय का T* p = new T[100];उपयोग करें, जैसे स्मार्ट पॉइंटर्स का उपयोग करें unique_ptr<T>और जैसे shared_ptr<T>कि कच्चे पॉइंटर्स आदि के बजाय विलोपन का ध्यान
रखें

8
धन्यवाद make_shared(c ++ 11) और make_unique(c ++ 14) आपके प्रोग्राम में शून्य का होना चाहिए newऔरdelete
sp2danny

2
अभी भी कुछ दुर्लभ मामले हो सकते हैं जिनके लिए नए / विलोपन की आवश्यकता होती है, जैसे परमाणु <T *>: परमाणु <unique_ptr <T >> की अनुमति नहीं है और परमाणु <share_ptr <T >> के पास ओवरहेड है जो कुछ मामलों में अस्वीकार्य हो सकता है।
atb

2
RAII का उपयोग करके संसाधन प्रबंधन के साथ एक वर्ग घोषित करने के लिए आपको नए को कॉल करने और सही हटाने की आवश्यकता है? या आप कह रहे हैं कि इसे छिपाने के लिए कुछ टेम्पलेट वर्ग भी है।
विनगार्सिया

2
@VinGarcia बिंदु यह है कि अधिकांश उपयोगकर्ता / ग्राहक (अर्थात: गैर-पुस्तकालय) कोड को कभी भी लिखना newया नहीं होना चाहिए delete। संसाधनों को प्रबंधित करने के लिए डिज़ाइन की गई कक्षाएं, जहां मानक घटक नौकरी नहीं कर सकते, बेशक वे क्या करने की आवश्यकता है, लेकिन मुद्दा यह है कि वे स्मृति के साथ बदसूरत सामान का प्रबंधन करते हैं, न कि अंत-उपयोगकर्ता कोड। इसलिए, अपनी खुद की लाइब्रेरी / हेल्पर क्लास करें new/ करें delete, और उनके बजाय उस क्लास का उपयोग करें।
अंडरस्कोर_ड

जवाबों:


265

deleteवैसे भी चेक करता है, इसलिए अपनी तरफ से जाँच करने से ओवरहेड जुड़ जाता है और बदसूरत दिखता है। एक बहुत अच्छा अभ्यास NULL के बाद पॉइंटर को सेट कर रहा है delete(दोहरे विलोपन और अन्य समान स्मृति भ्रष्टाचार समस्याओं से बचने में मदद करता है)।

मुझे भी अच्छा लगेगा अगर deleteडिफ़ॉल्ट रूप से पैरामीटर को NULL की तरह सेट किया जा रहा है

#define my_delete(x) {delete x; x = NULL;}

(मैं आर और एल मूल्यों के बारे में जानता हूं, लेकिन क्या यह अच्छा नहीं होगा?)


72
ध्यान दें कि अभी भी एक ही वस्तु को इंगित करने वाले कई अन्य बिंदु हो सकते हैं, भले ही आप विलोपन पर NULL को सेट करें।
sth

13
मेरे कोड में अधिकांश मामलों में, एक बार हटाए जाने के बाद सूचक कार्यक्षेत्र से बाहर हो जाता है। केवल NULL पर सेट करने से ज्यादा सुरक्षित है।
jalf

142
एक बहुत ही ईश्वर प्रैक्टिस डिलीट के बाद NULL को पॉइंटर सेट नहीं कर रहा है। इसे हटाने के बाद NULL के लिए एक पॉइंटर सेट करना मेमोरी एलोकेशन एरर को मिटा देता है, जो कि बहुत बुरी बात है। एक प्रोग्राम जो सही है, एक पॉइंटर को दो बार डिलीट नहीं करता है, और एक प्रोग्राम जो एक पॉइंटर को दो बार डिलीट करता है, क्रैश हो जाना चाहिए
डेमॉन

15
@ एलिस: यह अप्रासंगिक है कि मानक उस संबंध में क्या कहता है। मानक परिभाषित एक अशक्त सूचक को 30 साल पहले कुछ बेतुके कारण के लिए मान्य किया जा रहा है, इसलिए यह कानूनी (सबसे अधिक संभावना एक सी विरासत) है। लेकिन एक ही पॉइंटर को दो बार डिलीट करना (अपने बिट पैटर्न को बदलने के बाद भी) अभी भी एक गंभीर प्रोग्राम एरर है। मानक के शब्दों द्वारा नहीं, बल्कि कार्यक्रम तर्क और स्वामित्व के द्वारा। जैसा कि एक नल सूचक को हटा रहा है, चूंकि नल सूचक बिना किसी वस्तु के मेल खाता है , इसलिए संभवतः कुछ भी नहीं हटाया जा सकता है। एक कार्यक्रम होना चाहिए ठीक से पता कि क्या कोई वस्तु वैध है और कौन उसका मालिक है, और इसे कब हटाया जा सकता है।
डेमन

27
@ डैमोन हालांकि, आपके ड्रैकॉनियन स्वामित्व नियमों के इन निरस्त होने के बावजूद, लॉक मुक्त संरचनाएं लॉक आधारित लोगों की तुलना में काफी अधिक मजबूत हैं। और हां, मेरे सहकर्मी वास्तव में मुझे उन बढ़ी हुई निष्पादन प्रोफ़ाइल के लिए प्यार करते हैं जो ये संरचनाएं प्रदान करती हैं और कठोर धागा सुरक्षा जो वे बनाए रखती हैं, जो कोड (रखरखाव के लिए महान) के बारे में आसानी से अनुमति देती हैं। हालाँकि, इसमें से कोई भी और न ही आपके निहित व्यक्तिगत हमले का किसी भी प्रकार की शुद्धता, वैधता या स्वामित्व की परिभाषा से कोई लेना-देना नहीं है। आप जो प्रस्ताव देते हैं वह अंगूठे का एक अच्छा नियम है, लेकिन यह एक सार्वभौमिक कानून नहीं है और न ही यह मानक में निहित है।
ऐलिस

77

C ++ 0x ड्राफ्ट मानक से।

$ 5.3.5 / 2 - "[...] या तो विकल्प में, हटाने के ऑपरेंड का मूल्य एक शून्य सूचक मान हो सकता है। [... '"

बेशक, कोई भी कभी भी NULL मान वाले पॉइंटर का 'डिलीट' नहीं करेगा, लेकिन ऐसा करना सुरक्षित है। आदर्श रूप से किसी के पास ऐसा कोड नहीं होना चाहिए जो NULL पॉइंटर को हटाता है। लेकिन कभी-कभी यह उपयोगी होता है जब पॉइंटर्स का विलोपन (जैसे कंटेनर में) लूप में होता है। चूंकि NULL पॉइंटर वैल्यू को हटाना सुरक्षित है, इसलिए कोई भी डिलीट लॉजिक को NULL ऑपरेंड को डिलीट करने के लिए स्पष्ट जांच के बिना लिख ​​सकता है।

एक तरफ के रूप में, C मानक $ 7.20.3.2 यह भी कहता है कि NULL पॉइंटर पर 'फ्री' कोई कार्रवाई नहीं करता है।

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


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

47

हाँ यह सुरक्षित है।

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


चूंकि पिछले वाक्य ने भ्रम पैदा किया है, एक उदाहरण - जो अपवाद सुरक्षित नहीं है - जो वर्णित किया जा रहा है:

void somefunc(void)
{
    SomeType *pst = 0;
    AnotherType *pat = 0;

    
    pst = new SomeType;
    
    if (…)
    {
        pat = new AnotherType[10];
        
    }
    if (…)
    {
        code using pat sometimes
    }

    delete[] pat;
    delete pst;
}

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


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

1
@ ईजेपी: किसी कार्य की पूर्ण रूप से अनुमानित रूपरेखा नहीं हो सकती है void func(void) { X *x1 = 0; Y *y1 = 0; … x1 = new[10] X; … y1 = new[10] Y; … delete[] y1; delete[] x1; }:। मैंने कोई ब्लॉक स्ट्रक्चर या जंप नहीं दिखाया है, लेकिन delete[]शुरू में इनिशियलाइज़ेशन के कारण अंत में ऑपरेशन सुरक्षित हैं। यदि कुछ x1आवंटित होने के बाद अंत में कूद गया था और पहले y1आवंटित किया गया था और इसकी कोई आरंभीकरण नहीं था y1, तो अपरिभाषित व्यवहार होगा - और जबकि कोड हटाने से पहले अशक्तता ( x1और y1) के लिए परीक्षण कर सकता है , करने की कोई आवश्यकता नहीं है इसलिए।
जोनाथन लेफलर

22

अशक्त सूचक को हटाने का कोई प्रभाव नहीं पड़ता है। यह जरूरी नहीं है कि यह अच्छी कोडिंग शैली है, लेकिन यह बुरा भी नहीं है।

यदि आप अच्छी कोडिंग प्रथाओं की खोज कर रहे हैं, तो इसके बजाय स्मार्ट पॉइंटर्स का उपयोग करने पर विचार करें, तो आपको बिल्कुल भी ज़रूरत नहीं है delete


20
जिस समय लोग NULL पॉइंटर को हटाना चाहते हैं, जब वे सुनिश्चित नहीं होते हैं कि इसमें NULL शामिल है ... यदि उन्हें पता था कि यह NULL है तो वे डिलीट पर विचार नहीं करेंगे और इसलिए पूछ रहे हैं ;-)।
टोनी डेलरो

@ टिप्पणी: मेरा कहना केवल यह था कि इसका कोई प्रभाव नहीं होगा, और ऐसे कोड की उपस्थिति जो एक पॉइंटर को हटा देती है जिसमें कभी-कभी NULL होता है, जरूरी नहीं कि यह बुरा हो।
ब्रायन आर। बॉन्डी

3
IMO निरर्थक जाँच निश्चित रूप से खराब हैं, प्रदर्शन, पठनीयता और स्थिरता के लिए।
पल्म

@ अंपुल ओपी निश्चित रूप से उस तरह के बुरे, सेग फॉल्ट / यूबी तरह के बुरे के बारे में बात नहीं कर रहा है।
विंटर


3

जब तक आपने डिलीट ऑपरेटर को ओवरलोड नहीं किया है तब तक यह सुरक्षित है। यदि आपने डिलीट ऑपरेटर को ओवरलोड किया है और अशक्त स्थिति को नहीं संभाल रहा है तो यह बिल्कुल भी सुरक्षित नहीं है।


क्या आप अपने उत्तर के लिए कोई स्पष्टीकरण जोड़ सकते हैं?
मार्सिन नाबियालेक

-2

मैंने अनुभव किया है कि यह नहीं है [] NULL (यानी सरणी सिंटैक्स) को हटाना सुरक्षित (VS2010)। मुझे यकीन नहीं है कि यह सी ++ मानक के अनुसार है या नहीं।

यह है हटाने NULL (अदिश वाक्य रचना) के लिए सुरक्षित।


6
यह अवैध है, और मुझे विश्वास नहीं है।
कोनराड रुडोल्फ

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

3
(5.3.2 दूसरे विकल्प (डिलीट एरे) में, डिलीट के ऑपरेंड का मान एक नल पॉइंटर वैल्यू या एक पॉइंटर वैल्यू हो सकता है जो पिछले एरे न्यू-एक्सप्रेशन से उत्पन्न हुआ हो।
sp2danny

1
@Opux उत्तर में VS2010 का व्यवहार आरोपित। जैसा कि अन्य टिप्पणियों में बताया गया है, यह सुरक्षित है delete[] NULL
कोनराड रुडोल्फ

1
@Opux यही कारण है कि मैंने लिखा "मुझे विश्वास नहीं है" के बजाय "यह गलत है"। लेकिन मैं अभी भी नहीं है, और यह मानक का एक बहुत अपमानजनक, मूर्खतापूर्ण उल्लंघन होगा। वीसी ++ वास्तव में मानक प्रतिबंधों का पालन करने में वास्तव में बहुत अच्छा है, और जिन स्थानों पर यह उल्लंघन करता है वे ऐतिहासिक रूप से समझ में आते हैं।
कोनराड रुडोल्फ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.