2016-01-13 5 views
12

TQueue में किसी सरणी को संग्रहीत करने में समस्या आ रही है। कोई विचार जहां मैं गलत हो जाता हूं? कोड डेल्फी एक्सई 5 में ठीक काम करता है लेकिन डेल्फी 10 सिएटल में नहीं।टीक्यूयू में स्टोर सरणी संभव है?

(यदि यह एक बग है या यह कैसे काम करना चाहिए मैं तय नहीं कर सकता। कोशिश सुराग के लिए Embarcadero खोज लेकिन असफल रहे।)

procedure TForm1.Button1Click(Sender: TObject); 
var 
    FData: TQueue<TBytes>; 
    FsData: TQueue<String>; 

    arr: TBytes; 

begin 

    FData := TQueue<TBytes>.Create; 
    FsData := TQueue<String>.Create; 
    try 
    setlength(arr, 3); 
    arr[0] := 1; 
    arr[1] := 2; 
    arr[2] := 3; 

    FData.Enqueue(arr); 
    Memo1.Lines.Add('Count, array:' + IntToStr(FData.Count)); // 0? 

    FsData.Enqueue('asada'); 
    Memo1.Lines.Add('Count, string:' + IntToStr(FsData.Count)); // 1 
    finally 
    FData.Free; 
    FsData.Free; 
    end; 
end; 
+1

इसके अलावा, हमें अभी तक एक और असंगत बाइट सरणी प्रकार की आवश्यकता नहीं है। 'टीबीइट्स 'का प्रयोग करें। आमतौर पर 'बाइट' के अलावा तत्व प्रकारों के लिए 'TArray ' का उपयोग करें। –

+0

मैं सहमत हूं। मूल सरणी टिडबाइट्स (इंडी) – Hans

+1

काम नहीं करती है? –

उत्तर

20

यह एक दोष XE8 में शुरू की गई है। यहां सबसे सरल प्रजनन है जो मैं उत्पन्न कर सकता हूं।

{$APPTYPE CONSOLE} 

uses 
    System.Generics.Collections; 

var 
    Queue: TQueue<TArray<Byte>>; 

begin 
    Queue := TQueue<TArray<Byte>>.Create; 
    Queue.Enqueue(nil); 
    Writeln(Queue.Count); 
end. 

आउटपुट XE7 और सिएटल में XE7 और 0 में 1 है।

यह पहले ही एम्बरकैडेरो को सूचित किया गया है: RSP-13196


Enqueue के कार्यान्वयन इस तरह दिखता है:

procedure TQueue<T>.Enqueue(const Value: T); 
begin 
    if IsManagedType(T) then 
    if (SizeOf(T) = SizeOf(Pointer)) and (GetTypeKind(T) <> tkRecord) then 
     FQueueHelper.InternalEnqueueMRef(Value, GetTypeKind(T)) 
    else 
     FQueueHelper.InternalEnqueueManaged(Value) 
    else 
    case SizeOf(T) of 
    1: FQueueHelper.InternalEnqueue1(Value); 
    2: FQueueHelper.InternalEnqueue2(Value); 
    4: FQueueHelper.InternalEnqueue4(Value); 
    8: FQueueHelper.InternalEnqueue8(Value); 
    else 
    FQueueHelper.InternalEnqueueN(Value); 
    end; 
end; 

जब T एक गतिशील सरणी है, FQueueHelper.InternalEnqueueMRef शाखा चुना जाता है। यह बदले में इस तरह दिखता है: TTypeKind.tkDynArray के लिए कोई प्रविष्टि नहीं है

procedure TQueueHelper.InternalEnqueueMRef(const Value; Kind: TTypeKind); 
begin 
    case Kind of 
    TTypeKind.tkUString: InternalEnqueueString(Value); 
    TTypeKind.tkInterface: InternalEnqueueInterface(Value); 
{$IF not Defined(NEXTGEN)} 
    TTypeKind.tkLString: InternalEnqueueAnsiString(Value); 
    TTypeKind.tkWString: InternalEnqueueWideString(Value); 
{$ENDIF} 
{$IF Defined(AUTOREFCOUNT)} 
    TTypeKind.tkClass: InternalEnqueueObject(Value); 
{$ENDIF} 
    end; 
end; 

ध्यान दें कि वहाँ। चूंकि इन दो विधियों को रेखांकित किया गया है, इनलाइनर इसे सब कुछ कम करने के लिए संकुचित करता है। जब आप Enqueue गतिशील सरणी करते हैं तो कोई कार्रवाई नहीं की जाती है।

कोड इस तरह देखा XE7 के अच्छे पुराने दिनों में वापस

procedure TQueue<T>.Enqueue(const Value: T); 
begin 
    if Count = Length(FItems) then 
    Grow; 
    FItems[FHead] := Value; 
    FHead := (FHead + 1) mod Length(FItems); 
    Inc(FCount); 
    Notify(Value, cnAdded); 
end; 

वहाँ प्रकार विशिष्ट दोष के लिए कोई गुंजाइश।


मुझे नहीं लगता कि आपके लिए एक आसान कामकाज है। शायद आगे बढ़ने का सबसे सुविधाजनक तरीका XE7 TQueue के लिए कोड लेना और XE8 और सिएटल से टूटे हुए कार्यान्वयन के स्थान पर इसका उपयोग करना है। रिकॉर्ड के लिए, मैंने एम्बरकाडेरो जेनेरिक संग्रहों को छोड़ दिया है और अपनी कक्षाओं का उपयोग किया है।


पिछली कहानी यह है कि XE8 में, एम्बरकैडेरो ने जेनेरिक के कार्यान्वयन में कमी को संबोधित करने का निर्णय लिया। जब भी आप एक सामान्य प्रकार को तत्काल बनाते हैं, तो सभी विधियों की प्रतियां बनाई जाती हैं। कुछ तरीकों के लिए, अलग-अलग तत्कालताओं के लिए समान कोड उत्पन्न होता है।

तो यह समान कोड रखने के लिए TGeneric<TFoo>.DoSomething और TGeneric<TBar>.DoSomething के लिए काफी आम है। अन्य भाषाओं के लिए अन्य कंपाइलर, सी ++ टेम्पलेट्स, नेट जेनिक्स इत्यादि, इस डुप्लिकेशन को पहचानते हैं और समान जेनेरिक तरीकों को एक साथ मिलाते हैं। डेल्फी कंपाइलर नहीं करता है। अंतिम परिणाम सख्ती से जरूरी से एक बड़ा निष्पादन योग्य है।

XE8 Embarcadero में इस बात से निपटने का फैसला किया कि मैं पूरी तरह से गलत तरीका था। इस मुद्दे के मूल कारण पर हमला करने के बजाय, कंपाइलर, उन्होंने अपने सामान्य संग्रह वर्गों के कार्यान्वयन को बदलने का फैसला किया। यदि आप Generics.Collections में कोड देखते हैं, तो आप देखेंगे कि यह XE8 में पूरी तरह से फिर से लिखा गया है। जहां पहले XE7 और इससे पहले का कोड पठनीय था, XE8 से अब यह बहुत जटिल और अपारदर्शी है।इस निर्णय के निम्नलिखित परिणाम थे:

  1. जटिल कोड में कई त्रुटियां थीं। XE8 जारी होने के तुरंत बाद इनमें से कई पाए गए और तय किए गए हैं। आप एक और दोष पर ठोकर खाई है। एक चीज जिसे हमने सीखा है वह है कि एम्बरकाडेरो का आंतरिक परीक्षण सूट पर्याप्त रूप से अपने संग्रह वर्गों का प्रयोग नहीं करता है। यह स्पष्ट रूप से स्पष्ट है कि उनके परीक्षण अपर्याप्त हैं।
  2. कंपाइलर की बजाय अपनी लाइब्रेरी को बदलकर, उन्होंने आरटीएल कक्षाएं बनाई हैं। जेनेरिक कोड ब्लोट के साथ मूल मुद्दा तीसरे पक्ष के वर्गों के लिए बना हुआ है। अगर एम्बरकाडेरो ने स्रोत पर इस मुद्दे को ठीक किया था तो न केवल वे XE7 से सरल और सही संग्रह कक्षा कोड बनाए रख सकते थे, लेकिन सभी तीसरे जेनेरिक कोड को फायदा होगा।
+1

इसे सॉर्ट करने के लिए धन्यवाद – Hans

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