2011-10-04 12 views
10

में सुरक्षित रूप से कई ऑब्जेक्ट्स को कैसे बनाएं और नि: शुल्क कैसे करें आप कई वस्तुओं को सुरक्षित रूप से कैसे बनाएं और मुक्त कैसे करें?डेल्फी

मूल रूप से, बात इस तरह की:

newOrderSource := TWebNewOrderSource.Create(); 
    twData := TTWData.Create(); 
    webData := TWebData.Create(); 

    try 
    //do stuff 
    finally 
    newOrderSource.Free(); 
    twData.Free(); 
    webData.Free(); 
    end; 

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

उत्तर

15

आप एक कोशिश ब्लॉक के साथ ऐसा कर सकते हैं अगर आप पहले चर के शून्य आवंटित की तरह,

newOrderSource := nil; 
twData := nil; 
webData := nil; 
try 
    newOrderSource := TWebNewOrderSource.Create();  
    twData := TTWData.Create();  
    webData := TWebData.Create();  

    //do stuff  
finally  
    webData.Free();  
    twData.Free();  
    newOrderSource.Free();  
end;  

इसका कारण यह है Free() चेकों nil के लिए Self काम करता है।

+0

मैं एक बहुत ही इसी तरह उत्तर पोस्ट किया गया था, एक मामूली परिवर्तन डाल करने के लिए किया जाएगा 'newOrderSource: = TWebNewOrderSource.Create() ; कोशिश करने से पहले, और 'newOrderSource: = nil;' को हटा दें। –

+2

यह भी काम करता है और एक अनियंत्रित असाइनमेंट को हटा देता है लेकिन मैंने इस मामले में सादगी और स्थिरता का पक्ष लिया क्योंकि यह असाइनमेंट को सहेजने की अत्यधिक संभावना नहीं है यदि डेटाबेस में "सामान" कॉल करने पर बहुत अंतर आएगा। – chuckj

+6

मैं हर समय इसका उपयोग करता हूं लेकिन सुरक्षा के संबंध में, आपको ध्यान रखना चाहिए कि, ओपी के मूल कोड की तुलना में, यह आपको किसी एक कन्स्ट्रक्टर में उठाए गए अपवादों से बचाता है, लेकिन ** वस्तुओं को मुक्त करते समय उठाए गए अपवादों से ** ** नहीं। यदि आप इसके बारे में उलझन में हैं, तो आपका एकमात्र विकल्प है कि ऑब्जेक्ट्स के रूप में कई प्रयास करें/अंत में (या उन्हें इंटरफेस लागू करें और उन्हें दायरे से बाहर जाने दें)। –

10

मुझे यकीन है कि हर कोई जानता है कर रहा हूँ के रूप में, एक वस्तु के प्रबंधन के लिए मानक तरीका इस तरह है:

A := TMyObject.Create; 
try 
    A.DoSomething; 
finally 
    A.Free; 
end; 

अगर वहाँ TMyObject.Create में एक अपवाद तो नाशक बुलाया जाएगा और उसके बाद अपवाद उठाया है। उस स्थिति में A को असाइन नहीं किया जाएगा।

जब आप एक से अधिक ऑब्जेक्ट है आप पैटर्न को दोहरा सकते हैं:

A := TMyObject.Create; 
try 
    B := TMyObject.Create; 
    try 
    A.DoSomething; 
    B.DoSomething; 
    finally 
    B.Free; 
    end; 
finally 
    A.Free; 
end; 

यह बहुत जल्दी एक मेस और इसलिए सवाल बन जाता है।

एक मानक चाल इस तथ्य का लाभ उठाने के लिए है कि Free सुरक्षित रूप से nil ऑब्जेक्ट संदर्भ पर कॉल किया जा सकता है।

A := nil; 
B := nil; 
try 
    A := TMyObject.Create; 
    B := TMyObject.Create; 
    A.DoSomething; 
    B.DoSomething; 
finally 
    B.Free; 
    A.Free; 
end; 

यह मामूली कमजोरी है कि यह अपवाद B.Free में उठाया जा रहा करने के लिए लचीला नहीं है है लेकिन यह एक विफलता की स्थिति है कि अनदेखा किया जा सकता के रूप में इस संबंध को अनुचित नहीं है। विनाशकों को अपवाद नहीं उठाना चाहिए। यदि वे करते हैं तो आपकी प्रणाली शायद अप्रत्याशित रूप से टूट जाती है।

उपरोक्त यह पैटर्न थोड़ा गन्दा हो सकता है क्योंकि अधिक ऑब्जेक्ट्स जोड़े गए हैं इसलिए मैं व्यक्तिगत रूप से निम्न सहायक विधियों का उपयोग करता हूं।

procedure InitialiseNil(var Obj1); overload; 
procedure InitialiseNil(var Obj1, Obj2); overload; 
procedure InitialiseNil(var Obj1, Obj2, Obj3); overload; 

procedure FreeAndNil(var Obj1); overload; 
procedure FreeAndNil(var Obj1, Obj2); overload; 
procedure FreeAndNil(var Obj1, Obj2, Obj3); overload; 

वास्तव में मेरे कोड में और भी पैरामीटर के साथ संस्करण हैं। रखरखाव की आसानी के लिए यह कोड स्वचालित रूप से एक छोटी पायथन लिपि से उत्पन्न होता है।

ये विधियां स्पष्ट तरीके से लागू की गई हैं, उदा।

procedure FreeAndNil(var Obj1, Obj2); 
var 
    Temp1, Temp2: TObject; 
begin 
    Temp1 := TObject(Obj1); 
    Temp2 := TObject(Obj2); 
    Pointer(Obj1) := nil; 
    Pointer(Obj2) := nil; 
    Temp1.Free; 
    Temp2.Free; 
end; 

यह इस तरह से ऊपर नमूना फिर से लिखने के लिए हमें की अनुमति देता है:

InitialiseNil(A, B); 
try 
    A := TMyObject.Create; 
    B := TMyObject.Create; 
    A.DoSomething; 
    B.DoSomething; 
finally 
    FreeAndNil(B, A); 
end; 
+0

क्या आपके हेल्पर विधियों को मूल्यों की एक सरणी नहीं मिल सका ताकि आप उन्हें मनमाने ढंग से ऑब्जेक्ट्स पास कर सकें? –

+0

@ जेरी यह भी काम करेगा लेकिन मुझे इस बिंदु पर ओपन सरणी सिंटैक्स का उपयोग नहीं करना पसंद था। मेरा तर्क यह है कि ये कार्य एक बार लिखे जाते हैं और कभी संशोधित नहीं होते हैं। तो मैं संशोधित रहने वाले कोड में से अधिक की तुलना में नकल के बारे में कम ख्याल रखता हूं। प्रेरणा यह है कि कॉलिंग कोड क्लीनर है और वह कोड है जो संशोधित हो जाता है। –