Generische Klassenbibliothek - Bugs, Beschreibung, Fragen, Nutzungsmöglichkeiten und Vorschläge - Seite 29

 
Alexey Volchanskiy:

MSDN nennt es einen Ringpuffer, ich habe mir den Namen nicht ausgedacht.

Link zum

Alexey Navoykov:

...und endet mit einer Konvertierung in Argumente per Referenz, nicht nur per Wert.

Möglicherweise gibt es ein Problem mit den Literalen

 
TheXpert:

Link im Studio.

Möglicherweise gibt es ein Problem mit Literalen

Ich bin zu faul, den Artikel noch einmal zu suchen, aber ich habe ihn ein wenig gedehnt. Eine einfach oder doppelt verkettete Ringliste basiert auf einer verketteten Liste, aber das letzte Element speichert eine Verknüpfung zum allerersten Element.

 
TheXpert:

kann es zu Problemen mit den Literalen kommen

Nein, ich habe die Klasse "values" von der Basisklasse "reference" geerbt, nur als Wrapper. Wählen Sie also einfach die gewünschte Version der Klasse aus - und gehen Sie
 
Alexey Volchanskiy:

Eine einfache oder doppelte verknüpfte Liste basiert auf einer verknüpften Liste, aber das letzte Element in der verknüpften Liste speichert eine Verknüpfung mit dem allerersten Element.

Genau das ist der Punkt: Es ist ein "Basis"-Container, kein Ersatz-Container. Niemand hat die Entwickler daran gehindert, auch hier einen zusätzlichen Container einzubauen. Anstatt gemeinsame Begriffe zu ersetzen
 
Alexey Navoykov:

Wahrscheinlich hat derjenige, der diese Klassen portiert hat, einfach beschlossen, sich das Leben zu erleichtern, indem er den Code vereinfacht hat. Statt zwei Zeigern m_first und m_last hat er einen Zeiger m_head gemacht...

Ich habe mir die Dotnet-Quellen angesehen und den Grund erkannt: Die LinkedList-Klasse selbst ist korrekt portiert, es gibt nur einen Zeigerkopf, der sowohl der Anfang als auch das Ende ist. Die interne Implementierung ist also tatsächlich in einer Schleife, aber das externe Verhalten ist es nicht. MQ hat einen Fehler in der CLinkedNode-Klasse (Next- und Previous-Methoden). So sieht ihre ursprüngliche Implementierung aus:

        public LinkedListNode<T>? Next
        {
            get { return next == null || next == list!.head ? null : next; }
        }

        public LinkedListNode<T>? Previous
        {
            get { return prev == null || this == list!.head ? null : prev; }
        }

Und so wird es auf MQL portiert:

   CLinkedListNode<T>* Next(void)                      { return(m_next); }
   CLinkedListNode<T>* Previous(void)                  { return(m_prev); }

Vielleicht waren sie unaufmerksam und haben es falsch verstanden.

Generell bin ich aber auch etwas verwundert über die Dotnet-Implementierung: Warum war es nicht möglich, in der Liste selbst zwei Zeiger zu setzen (erster und letzter) statt nur einen Kopf. Das würde zusätzliche Überprüfungen in den obigen Methoden der Listenknoten vermeiden, d.h. sie würden genau so aussehen wie MQ jetzt, aber alles würde richtig funktionieren. Natürlich würde es den Prozess des Einfügens/Löschens von Knoten etwas verlangsamen, aber es würde die Iteration über sie beschleunigen, was eine viel höhere Priorität hat. Next und Previous werden definitiv häufiger aufgerufen, als hinzugefügte Knoten. So habe ich es gemacht, und ich dachte, das würde auch für melkomsoft gelten (aber egal).

Übrigens, MQ hat einen weiteren Fehler in der Implementierung von CLinkedListNode und CRedBlackTreeNode. (außer m_value) sollen ausschließlich von der Listenklasse selbst geändert werden. Niemand sonst muss sie ändern. Deshalb sind sie in dotnet interne Felder. MQ hat öffentliche Methoden erstellt, um diese Felder zu ändern, und zumindest hätten sie ihnen einen spezifischen Namen gegeben... aber nein, nur die üblichen Namen:

void              Next(CLinkedListNode<T>*value)     { m_next=value; }
 

Hallo zusammen!

Gibt es eine andere Möglichkeit, Elemente in der CHashMap zu löschen, als sie über CopyTo zu kopieren und manuell zu löschen?

 

Hier sind noch ein paar andere Dinge, um den Ofen der schlechten Implementierung der Bibliothek zu versenken. Ihre Klasse CKeyValuePair erbt aus irgendeinem Grund die Schnittstelle IComparable (und damit auch IEqualityComparable), was voraussetzt, dass der Benutzertyp Key diese Schnittstellen ebenfalls unterstützt. Obwohl es keinen Bedarf dafür gibt, wenn wir unseren eigenen Comparer definieren. Im Original hat KeyValuePair natürlich überhaupt keine Schnittstellen.

Wenn du weiter stöberst, wirst du noch seltsamere Dinge finden:

template<typename TKey,typename TVal>
CHashMap::CHashMap(IEqualityComparer<TKey>*comparer): m_count(0),
                                                      m_free_list(0),
                                                      m_free_count(0),
                                                      m_capacity(0)
  {
//--- check equality comaprer
   if(CheckPointer(comparer)==POINTER_INVALID)
     {
      //--- use default equality comaprer    
      m_comparer=new CDefaultEqualityComparer<TKey>();
      m_delete_comparer=true;
     }
   else
     {
      //--- use specified equality comaprer
      m_comparer=comparer;
      m_delete_comparer=false;
     }
  }

Wenn Sie z.B. versehentlich einen kaputten Zeiger in den Konstruktor geben, wird das Programm nicht nur in Ruhe weiterarbeiten, sondern auch seine Logik ändern!

Der Konstruktor sollte wie folgt aussehen:

template<typename TKey,typename TVal>
CHashMap::CHashMap(IEqualityComparer<TKey>*comparer): m_count(0),
                                                      m_free_list(0),
                                                      m_free_count(0),
                                                      m_capacity(0),
                                                      m_comparer(comparer),
                                                      m_delete_comparer(false)
{ }

Und keinPOINTER_INVALID . Und es gibt eine andere Konstruktorsignatur für den Standardkomparator.

 
Gibt es ein Beispiel für die korrekte Anwendung einer CQueue<T>-Vorlage mit einer beliebigen Klasse als T-Parameter?
 
Wurde bereits in einem parallelen Thread behandelt. Beantragen Sie ein Verbot.
 

Können Sie mir sagen, warum sich der Code nicht kompilieren lässt?

#include <Generic\HashMap.mqh>
void OnStart()
  {
   CHashMap<ENUM_CHART_PROPERTY_INTEGER,int> mapI;    // эта срока компилируется без ошибок
   CHashMap<ENUM_CHART_PROPERTY_DOUBLE,double> mapD;  // здесь ошибки компиляции: 'NULL' - cannot convert enum  HashMap.mqh     21      39. 'NULL' - cannot convert enum        HashMap.mqh     462     30
   CHashMap<ENUM_CHART_PROPERTY_STRING,string> mapS;  // здесь ошибки компиляции: 'NULL' - cannot convert enum  HashMap.mqh     21      39. 'NULL' - cannot convert enum        HashMap.mqh     462     30

  }

Das Problem ist in System-Enums: ENUM_CHART_PROPERTY_DOUBLE, ENUM_CHART_PROPERTY_STRING etwas ist falsch mit ihnen. Wenn ich meine eigene Aufzählung als Schlüsseltyp verwende, funktioniert die Kompilierung ebenfalls.