2011-02-26 16 views
5

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

कोई विचार? सहायता बहुत सराहना की है।


प्रकार परिभाषा:

TPointer = ^TAccessoryItem; 
TAccessoryItem = Record 
    Id : Integer; 
    PartNumber : String; 
    Qty : Integer; 
    Description : String; 
    Previous : Pointer; 
    Next : Pointer; 
end; 

Procedure TAccessoryList._clone (Var copy : TAccessoryItem; Var original : TAccessoryItem); 

begin 

    copy.Id := original.Id; 
    copy.Qty := original.Qty; 
    copy.Partnumber := original.Partnumber; **// Access errors happens here** 
    copy.Next := Nil; 
    copy.Previous := Nil; 

    end; 

कॉलिंग नीचे आवेदन:

procedure TAccessoryList.AddItem(Var Item : TAccessoryItem); 

Var 

    newItem : ptrAccessoryItem; 

begin 

    GetMem(newItem, sizeOf(TAccessoryItem)); 

    _clone(newItem^, Item); 

end; 

उत्तर

20

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

FillChar(newItem^, sizeof(TAccessoryItem), 0)

कॉल करने के लिए, की जरूरत है।

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

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

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

डेल्फी में रिकॉर्ड आवंटित करने के लिए सबसे अच्छा तरीका है नई() फ़ंक्शन का उपयोग करने के लिए है:

New(newItem); 

संकलक सूचक के प्रकार से आवंटन का आकार (क्या सूचक प्रकार अंक sizeof करने के लिए) का अनुमान लगा होगा , स्मृति आवंटित करें, और सभी क्षेत्रों को आपके लिए उचित रूप से प्रारंभ करें।

Dispose(newItem); 

यह सुनिश्चित करें कि रिकॉर्ड के सभी संकलक से प्रबंधित खेतों रिकॉर्ड अपने आप में इस्तेमाल किया स्मृति को मुक्त कराने के अलावा सही ढंग से निपटाया जाता है कर देगा:

इसी deallocator निपटान() फ़ंक्शन है ।

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

कंपाइलर प्रबंधित प्रकारों में लंबे तार ("स्ट्रिंग", "स्ट्रिंग [10]" नहीं), विस्तृत स्ट्रिंग्स, वेरिएंट्स, इंटरफेस, और शायद कुछ भूल गए हैं।

इस बारे में सोचने का एक तरीका यह है: GetMem/FreeMem बस स्मृति के ब्लॉक आवंटित और रिलीज़ करें। वे इस बारे में कुछ भी नहीं जानते कि उस ब्लॉक का उपयोग कैसे किया जाएगा। नया और निपटान, हालांकि, आप आवंटित या स्मृति को मुक्त करने के प्रकार के "जागरूक" हैं, इसलिए वे यह सुनिश्चित करने के लिए कोई अतिरिक्त कार्य करेंगे कि सभी आंतरिक हाउसकीपिंग को स्वचालित रूप से ख्याल रखा जाता है।

सामान्यतः, GetMem/FreeMem से बचने के लिए सबसे अच्छा है, जब तक कि आपको वास्तव में आवश्यकता नहीं है, इसके साथ जुड़े किसी भी प्रकार के अर्थशास्त्र के साथ स्मृति की कच्ची ब्लॉक नहीं है।

+0

यदि किसी कारण से आप नए() का उपयोग नहीं करना चाहते हैं, तो AllocMem() http://delphi.wikia.com/wiki/AllocMem_Routine का उपयोग करें, यह GetMem() के बाद शॉर्टकट से अधिक कुछ नहीं है, इसके बाद फिलर ()। – arthurprs

+2

मैं 'फिलरहर' पर 'आरंभ करें' की सिफारिश करता हूं - "स्मृति के कच्चे ब्लॉक के साथ जुड़े किसी भी प्रकार के अर्थशास्त्र के साथ।" और जो चीज आप भूल गए वह गतिशील सरणी थी। –

+0

डेल्फी के सवालों का जवाब देने के लिए मीठा, डैनी! –

2

भी रिकॉर्ड मूल्य प्रकार के होते हैं (जैसा कि TObject तरह प्रकार के संदर्भ के खिलाफ), ताकि आप केवल

AccessoryItem1 := AccessoryItem2; 

(या AccessoryItem1 ^: = AccessoryItem2^अगर वे संकेत दिए गए हैं) कर सकते हैं

और कहीं भी होगी अपने लिए सभी क्षेत्रों की प्रतिलिपि बनाएँ।

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

+1

स्पष्ट रूप से पॉइंटर्स का उपयोग करने के बजाय डेल्फी में var या const के रूप में पारित करना बेहतर है। –

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