2010-08-18 7 views
11

मैंने A case against FreeAndNil पढ़ा है लेकिन अभी भी समझ में नहीं आता है कि मैं इस विधि का उपयोग कक्षा विनाशक में क्यों नहीं कर सकता? क्या कोई समझा सकता है।मुझे विनाशक में नि: शुल्क और फ्री और नील का उपयोग क्यों करना चाहिए?

अद्यतन: मुझे लगता है कि Eric Grange से टिप्पणी मेरे लिए सबसे उपयोगी थी। लिंक दिखाता है कि यह स्पष्ट नहीं है कि इससे कैसे निपटें और यह मुख्य रूप से स्वाद का विषय है। इसके अलावा विधि FreeAndInvalidate उपयोगी था।

+0

आप एक अच्छा सवाल यहाँ पूछा। – Ampere

उत्तर

14

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

यह तर्क देता है कि यह आपके पास वास्तविक समस्या को छुपाता है। इसका मतलब यह होना चाहिए कि आपका कोड किसी वस्तु के गुण/फ़ील्ड/विधियों तक पहुंच रहा है जो पहले ही नष्ट हो चुका है (विनाशक कहा जाता है)। तो FreeAndNil के साथ वास्तविक समस्या को छिपाने के बजाय आपको वास्तव में अंतर्निहित समस्या को हल करना चाहिए।

यदि आप FreeONject PropertyA को SomeObject के विनाशक में उपयोग करेंगे तो नीचे दिया गया यह कोड क्रैश नहीं होगा। लेकिन यह वास्तविक समस्या को छुपाता है कि कुछ ऑब्जेक्ट का उपयोग नष्ट होने के बाद किया जाता है। इसे छिपाने के बजाय इस डिजाइन समस्या (नष्ट वस्तुओं को एक्सेस करना) को हल करना बेहतर है।

SomeObject.Free; // Destructor called 
if Assigned(SomeObject.PropertyA) then // SomeObject is destroyed, but still used 
    SomeObject.PropertyA.Method1; 

संपादित

अन्य मामले पर, एक बहस कर सकते हैं कि अगर FreeAndNil नहीं किया जाता है, कोड या तो दुर्घटना नहीं होगा। चूंकि ऑब्जेक्ट नष्ट हो गया है, फिर भी स्मृति का पुन: उपयोग नहीं किया जा सकता है और सभी संरचनाएं सामंजस्य में हो सकती हैं। ऊपर दिए गए कोड को बिना किसी समस्या के चलाया जा सकता है यदि FreeAndNil के बजाय PropertyA को नष्ट करने के लिए नि: शुल्क उपयोग किया जाता है।

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

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

+0

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

+4

सुरक्षा के लिए, आप संदर्भ को अमान्य बनाने के लिए 'फ्री एंड इनवालिडेट' (http://delphitools.info/2010/02/06/dont-abuse-freeandnil-anymore/) जैसे कुछ का उपयोग कर सकते हैं, न केवल शून्य, ताकि सभी आगे प्रयास करें ऑब्जेक्ट तक पहुंचने के लिए अपवाद ट्रिगर होगा। –

+0

लिंक के लिए धन्यवाद। यह मुझे कुछ अंतर्दृष्टि देता है। एरिक ग्रेंज के लिए –

7

समस्या को समझाने में काफी आसान है, और इस मुद्दे के आसपास की विवाद उद्देश्य से अधिक व्यक्तिपरक है। दिए गए कारण के लिए,

procedure Test; 
var 
    LObj: TObject; 
begin 
    LObj := TObject.Create; 
    try 
    {...Do work...} 
    finally 
    //The LObj variable is going out of scope here, 
    // so don't bother nilling it. No other code can access LObj. 

    //FreeAndNil(LObj); 
    LObj.Free; 
    end; 
end; 

ऊपर कोड स्निपेट में, nilling LObj चर व्यर्थ होगा: FreeAndNil के उपयोग के बस अनावश्यक अगर वस्तु मुक्त कर दिया जा रहा है चर संदर्भ क्षेत्र से बाहर जाना होगा है। हालांकि, यदि किसी ऑब्जेक्ट वैरिएबल को एप के जीवनकाल के दौरान कई बार तत्काल और मुक्त किया जा सकता है, तो यह जांचना आवश्यक हो जाता है कि ऑब्जेक्ट वास्तव में तत्काल है या नहीं। यह जांचने का आसान तरीका यह है कि ऑब्जेक्ट संदर्भ nil पर सेट किया गया है या नहीं। nil पर सेटिंग को सुविधाजनक बनाने के लिए, FreeAndNil() विधि दोनों संसाधनों को मुक्त करेगी, और आपके लिए nil सेट करेंगी।फिर, कोड में आप यह देखने के लिए जांच सकते हैं कि ऑब्जेक्ट LObj = nil या Assigned(LObj) के साथ तत्काल है या नहीं।

कि क्या वस्तु विनाशकर्ता में .Free या FreeAndNil() उपयोग करने के लिए के मामले एक ग्रे क्षेत्र है, लेकिन अधिकांश भाग के लिए, .Free सुरक्षित होना चाहिए, और नाशक में उप वस्तुओं के लिए संदर्भ nilling अनावश्यक होना चाहिए। रचनाकारों और विनाशकों में अपवादों से निपटने के तरीके के बारे में विभिन्न तर्क हैं।

अब ध्यान देना: यदि आप ले सकते हैं और कि क्या .Free या FreeAndNil() ऊपर उल्लिखित विशिष्ट परिस्थितियों के आधार पर उपयोग करने के लिए, यह ठीक है चुनते हैं, लेकिन ध्यान दें कि एक बग की लागत की वजह से नहीं एक मुक्त कर दिया ऑब्जेक्ट संदर्भ nilling करना पसंद करते हैं बाद में इसका उपयोग किया जा सकता है बहुत अधिक हो सकता है। यदि पॉइंटर को बाद में एक्सेस किया जाता है (ऑब्जेक्ट मुक्त हो जाता है लेकिन संदर्भ शून्य पर सेट नहीं होता है), तो ऐसा हो सकता है कि आप दुर्भाग्यपूर्ण हैं और स्मृति भ्रष्टाचार का पता लगाना कोड की कई पंक्तियों को मुक्त-लेकिन-रहित ऑब्जेक्ट संदर्भ तक पहुंच से दूर करता है। इस प्रकार की बग को ठीक करने में बहुत लंबा समय लग सकता है, और हाँ, मुझे पता है कि फास्टएमएम का उपयोग कैसे करें।

इसलिए मेरे साथ कुछ लोगों के लिए, यह आदत बनने के लिए आदत (आलसी एक, शायद) बन गई है, जब वे मुक्त हो जाते हैं, भले ही न तो सख्ती से जरूरी हो।

+0

आप एक ऐसे मामले का इलाज कर रहे हैं जहां आपके पास एक छोटी सी प्रक्रिया है जहां परिवर्तक गुंजाइश से बाहर हो जाता है। उससे भी ज्यादा है। लेकिन +1, मैं FreeAndNil का उपयोग करने के साथ सहमत हूं। – Ampere

+0

@Altar: मैंने इस उदाहरण का चयन किया क्योंकि यह सबसे अच्छी स्थिति प्रदान करता है जिसमें यह तर्क दिया जा सकता है कि "फ्री" "फ्री एंड नील" से बेहतर है। अन्य सभी स्थितियां कम सटीक हैं। दोहराने के लिए: ऑब्जेक्ट इंस्टेंस को नष्ट करते समय मैं हमेशा अपने ऑब्जेक्ट संदर्भों को शून्य करता हूं, ताकि मुझे कभी सोचना न पड़े कि मुझे क्या चाहिए या नहीं। –

5

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

TSomething से इंटरफ़ेस प्रकार ISomething पर एक चर के प्रकार को बदलने के बाद मुझे कई बार काट दिया गया। FreeAndNil इंटरफ़ेस चर पर शिकायत नहीं करता है और खुशी से अपना काम जारी रखता है। यह कभी-कभी रहस्यमय दुर्घटनाओं का कारण बनता है जिसे तुरंत उस जगह पर वापस नहीं किया जा सकता था जहां यह हुआ और खोजने में कुछ समय लगा।

तो मैंने Free पर कॉल करने के लिए वापस स्विच किया। और जब मुझे यह आवश्यक लगता है तो मैं चर को बाद में nil पर सेट करता हूं।

3

मैं एक stackoverflow सवाल FreeAndNil के बारे में और FreeAndInvalidate बात कर उल्लेख करने के लिए शिकार किया कि माइक्रोसॉफ्ट सुरक्षा डेवलपमेंट लाइफ साइकल अब recommends something similar to FreeAndInvalidate:

ऊपर एसडीएल सिफारिश के प्रकाश में - और का पुन: उपयोग से संबंधित वास्तविक कीड़े की एक संख्या हटाए गए सी ++ ऑब्जेक्ट्स के बालों के संदर्भ ...

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

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

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

तो मूल रूप से:

procedure FreeAndInvalidate(var obj); 
var 
    temp : TObject; 
const 
    INVALID_ADDRESS = $8123; //address on same page as zero address (nil) 
begin 
    //Note: Code is public domain. No attribution required. 
    temp := TObject(obj); 
    Pointer(obj) := Pointer(INVALID_ADDRESS); 
    temp.Free; 
end; 
संबंधित मुद्दे