2009-02-27 9 views
6

में पॉइंटर्स का उपयोग करना मैं अब कुछ समय से विकास कर रहा हूं, और मैंने अब तक अपने विकास में पॉइंटर्स का उपयोग नहीं किया है।डेल्फी

तो पॉइंटर्स के क्या फायदे हैं? क्या कोई एप्लिकेशन तेजी से चलता है या कम संसाधनों का उपयोग करता है?

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

उत्तर

30

एक सूचक एक चर है जो स्मृति के एक टुकड़े को इंगित करता है। फायदे हैं:

  • आप स्मृति के उस टुकड़े आकार आप चाहते हैं दे सकते हैं।
  • आपको केवल स्मृति के एक अलग टुकड़े को इंगित करने के लिए एक सूचक को बदलना होगा जो बहुत समय कॉपी करने में बचाता है।

डेल्फी बहुत सारे छुपे पॉइंटर्स का उपयोग करता है। उदाहरण के लिए, आप उपयोग कर रहे हैं:

var 
    myClass : TMyClass; 
begin 
    myClass := TMyClass.Create; 

myClass वस्तु के लिए सूचक है।

एक अन्य उदाहरण गतिशील सरणी है। यह भी एक सूचक है।

पॉइंटर्स के बारे में और अधिक समझने के लिए, आपको स्मृति के बारे में अधिक समझने की आवश्यकता है। डेटा के प्रत्येक टुकड़े डेटा के विभिन्न टुकड़ों में मौजूद हो सकते हैं।

उदाहरण के लिए वैश्विक चर:

unit X; 

interface 

var 
    MyVar: Integer; 

एक वैश्विक चर datasegment में परिभाषित किया गया है। डेटासेजमेंट तय किया गया है। और कार्यक्रम के जीवनकाल के दौरान ये चर उपलब्ध हैं। जिसका अर्थ है कि स्मृति का उपयोग अन्य उपयोगों के लिए नहीं किया जा सकता है।

स्थानीय चर:

procedure Test; 
var 
    MyVar: Integer; 

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

ढेर चर:

procedure Test2; 
var 
    MyClass: TMyClass; 
begin 
    MyClass := TMyClass.Create; 

चर MyClass एक सूचक (जो एक स्थानीय चर कि ढेर पर परिभाषित किया जाता है) है। किसी वस्तु का निर्माण करके आप ढेर पर स्मृति का एक टुकड़ा आवंटित करते हैं ('अन्य' स्मृति का बड़ा टुकड़ा जिसे प्रोग्राम और ढेर के लिए उपयोग नहीं किया जाता है)। परिवर्तनीय MyClass में स्मृति के इस टुकड़े का पता है। ढेर चर मौजूद हैं जब तक आप उन्हें छोड़ नहीं देते। इसका मतलब यह है कि यदि आप वस्तु को मुक्त किए बिना funcion Test2 से बाहर निकलें, तो वस्तु अभी भी ढेर पर मौजूद है। लेकिन आप इसे एक्सेस नहीं कर पाएंगे क्योंकि पता (परिवर्तनीय MyClass) चला गया है।

सर्वश्रेष्ठ अभ्यास

यह लगभग हमेशा बेहतर आवंटन और एक ही स्तर पर एक सूचक चर पुनःआवंटन लिए है।

उदाहरण के लिए:

var 
    myClass: TMyClass; 
begin 
    myClass := TMyClass.Create; 
    try 
    DoSomething(myClass); 
    DoSomeOtherthing(myClass); 
    finally 
    myClass.Free; 
    end; 
end; 

आप उन कार्यों को एक वस्तु का एक उदाहरण लौटने से बचने की कोशिश कर सकते हैं। यह कभी निश्चित नहीं है कि कॉलर को ऑब्जेक्ट का निपटान करने की आवश्यकता है। और यह स्मृति रिसाव या दुर्घटनाओं बनाता है।

+0

आशा है कि यह पर्याप्त जानकारी है, यदि आप चाहें तो मैं और जोड़ सकता हूं। –

+0

+1 उत्कृष्ट स्पष्टीकरण। अच्छा कार्य! –

+0

धन्यवाद, मुझे मदद करना पसंद है। लेकिन अगर यह अनुचित है तो यह हमेशा अच्छा होता है। –

2

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

पॉइंटर्स के फायदों के लिए गेमकैट जवाब देखें।

इस About.com article में आप डेल्फी में पॉइंटर्स का मूल स्पष्टीकरण पा सकते हैं।

2

कुछ डेटा संरचनाओं के लिए पॉइंटर्स आवश्यक हैं। सबसे सरल उदाहरण एक लिंक्ड सूची है। ऐसी संरचनाओं का लाभ यह है कि आप स्मृति में उन्हें स्थानांतरित किए बिना तत्वों को पुन: संयोजित कर सकते हैं। उदाहरण के लिए आप बड़ी जटिल वस्तुओं की एक लिंक्ड सूची प्राप्त कर सकते हैं और उनमें से किसी भी को बहुत जल्दी स्वैप कर सकते हैं क्योंकि आपको वास्तव में इन ऑब्जेक्ट्स को स्थानांतरित करने के बजाय दो पॉइंटर्स समायोजित करना होगा।

यह ऑब्जेक्ट पास्कल (डेल्फी) सहित कई भाषाओं पर लागू होता है।

10

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

मुझे डेल्फी में पॉइंटर उपयोग के दो उदाहरण दें। यदि आप अधिकतर व्यावसायिक ऐप्स लिखते हैं तो आप देखेंगे कि यह शायद आपके लिए प्रासंगिक नहीं है। हालांकि, यदि आपको कभी भी किसी भी मानक डेल्फी इकाइयों द्वारा आयात नहीं किया जाता है, और जिसके लिए कोई आयात इकाई (उदाहरण के लिए) जेडीआई पुस्तकालयों को पाया जा सकता है, तो यह तब भी महत्वपूर्ण हो सकता है जब आपको कभी भी Windows या तृतीय पक्ष API फ़ंक्शंस का उपयोग करने की आवश्यकता हो। और स्ट्रिंग-प्रोसेसिंग कोड में उस आवश्यक अंतिम बिट की गति को प्राप्त करने की कुंजी हो सकती है।

प्वाइंटर को भिन्न आकारों की डेटा प्रकार (संकलन समय पर अज्ञात) से निपटने के लिए

विंडोज बिटमैप डेटा प्रकार पर विचार किया जा सकता है। प्रत्येक छवि में अलग-अलग चौड़ाई और ऊंचाई हो सकती है, और 2^4, 2^8, 2^16, 2^24 या यहां तक ​​कि 2^32 ग्रे मानों या रंगों से काले और सफेद (1 बिट प्रति पिक्सेल) से लेकर विभिन्न प्रारूप होते हैं। । इसका मतलब यह है कि यह संकलित समय पर अज्ञात है कि बिटमैप कितनी मेमोरी पर कब्जा करेगा।

windows.pas में TBitmapInfo प्रकार है:

type 
    PBitmapInfo = ^TBitmapInfo; 
    tagBITMAPINFO = packed record 
    bmiHeader: TBitmapInfoHeader; 
    bmiColors: array[0..0] of TRGBQuad; 
    end; 
    TBitmapInfo = tagBITMAPINFO; 

TRGBQuad तत्व में एक अकेला पिक्सेल का वर्णन करता है, लेकिन बिटमैप एक से अधिक पिक्सेल होते हैं निश्चित रूप से करता है।इसलिए भी इसे करने के लिए प्रकार TBitmapInfo की एक स्थानीय चर, लेकिन हमेशा एक सूचक का प्रयोग करेंगे कभी नहीं:

var 
    BmpInfo: PBitmapInfo; 
begin 
    // some other code determines width and height... 
    ... 
    BmpInfo := AllocMem(SizeOf(TBitmapInfoHeader) 
    + BmpWidth * BmpHeight * SizeOf(TRGBQuad)); 
    ... 
end; 

अब सूचक का उपयोग कर आप सभी पिक्सल का उपयोग कर सकते हैं, भले ही TBitmapInfo केवल एक ही एक है। ध्यान दें कि इस तरह के कोड के लिए आपको रेंज जांच अक्षम करना होगा।

इस तरह की सामग्री को भी TMemoryStream कक्षा के साथ संभाला जा सकता है, जो मूल रूप से स्मृति के एक ब्लॉक के लिए एक सूचक के आसपास एक दोस्ताना आवरण है।

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

प्वाइंटर स्ट्रिंग कार्रवाइयों को गति देने के लिए इस्तेमाल किया जा सकता है

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

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

एक तार के नहीं-तो-अच्छा संपत्ति है कि वे संदर्भ बार गणना कर रहे हैं। प्रत्येक ऑपरेशन जो स्ट्रिंग को संभवतः संशोधित कर सकता है, यह सुनिश्चित करना है कि संदर्भ गणना 1 है, क्योंकि स्ट्रिंग में अन्यथा संशोधन खतरनाक होगा। एक स्ट्रिंग में एक चरित्र को बदलना एक संशोधन है। सुनिश्चित करें कि संदर्भ गणना 1 होगी UniqueString() संकलक जब भी एक स्ट्रिंग में एक चरित्र के लिए लिखा है द्वारा जोड़ा जाता है करने के लिए कॉल करने के लिए। अब एक पाश में एक स्ट्रिंग की n वर्ण लिख UniqueString() कारण होगा n बार के नाम से जाना है, भले ही बाद पहली बार है आश्वासन दिया है कि संदर्भ गिनती है 1. इस मूल रूप से इसका मतलब है n - 1 UniqueString की कॉल() अनावश्यक रूप से प्रदर्शन कर रहे हैं।

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

procedure MakeSpacesVisible(const AValue: AnsiString): AnsiString; 
var 
    P: PAnsiChar; 
begin 
    Result := AValue; 
    P := PAnsiChar(Result); 
    while P[0] <> #0 do begin 
    if P[0] = ' ' then 
     P[0] := $B7; 
    Inc(P); 
    end; 
end; 

दूसरा समारोह में साथ कोड इस कोड

procedure MakeSpacesVisible(const AValue: AnsiString): AnsiString; 
var 
    i: integer; 
begin 
    Result := AValue; 
    for i := 1 to Length(Result) do begin 
    if Result[i] = ' ' then 
     Result[i] := $B7; 
    end; 
end; 

के लिए मार डाला तुलना नहीं होगा केवल एक कॉल UniqueString(), जब करने के लिए पहले स्ट्रिंग वर्ण का पता चार सूचक को सौंपा गया है।