Libreria di classi generiche - bug, descrizione, domande, caratteristiche d'uso e suggerimenti - pagina 29

 
Alexey Volchanskiy:

MSDN lo chiama ring buffer, non ho inventato io il nome.

collegamento al

Alexey Navoykov:

...e finendo con una conversione degli argomenti per riferimento, non solo per valore.

potrebbe esserci un problema con i letterali

 
TheXpert:

collegamento in studio.

Potrebbe esserci un problema con i letterali

Pigro per cercare di nuovo quell'articolo, ma l'ho allungato un po'. Una lista linkata singola o doppia ad anello è basata su una lista linkata, ma l'ultimo elemento memorizza un collegamento al primo.

 
TheXpert:

ci possono essere problemi con i letterali

No, ho la classe "values" ereditata dalla classe base "reference", puramente come wrapper. Quindi basta selezionare la versione richiesta della classe - e andare
 
Alexey Volchanskiy:

Una lista collegata singola o doppia è basata su una lista collegata, ma l'ultimo elemento della lista collegata memorizza un collegamento al primo elemento.

Questo è il punto: è una "base", non una sostituzione. Nessuno ha impedito agli sviluppatori di farne un contenitore aggiuntivo anche qui. Invece di sostituire i concetti comuni
 
Alexey Navoykov:

Molto probabilmente, chi ha portato queste classi ha deciso di semplificarsi la vita semplificando il codice: invece di due puntatori m_primo e m_ultimo ha fatto un solo puntatore m_testa...

Guardando i sorgenti di dotnet, ho capito il motivo: la classe LinkedList è stata portata correttamente, c'è solo una testa del puntatore, che è sia l'inizio che la fine. Quindi l'implementazione interna è effettivamente in loop, ma il comportamento esterno no. MQ ha un errore nella classe CLinkedNode (metodi Next e Previous). Ecco come appare la loro implementazione originale:

        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; }
        }

Ed ecco come viene portato in MQL:

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

Forse sono stati disattenti e hanno sbagliato.

Ma in generale sono anche un po' sorpreso dell'implementazione di dotnet. Perché non era possibile fare due puntatori nella lista stessa (primo e ultimo) invece di una sola testa. Questo eviterebbe controlli extra nei metodi sopra citati del nodo della lista, cioè avrebbero esattamente l'aspetto di MQ ora, ma tutto funzionerebbe correttamente. Naturalmente questo rallenterebbe il processo di inserimento/cancellazione dei nodi, ma accelererebbe l'iterazione su di essi, che è una priorità molto più alta. Next e Previous sono sicuramente chiamati più spesso dei nodi aggiunti. È così che ho fatto, ho pensato che lo stesso sarebbe stato per melkomsoft. Ma non importa )

A proposito, MQ ha un altro bug nell'implementazione di CLinkedListNode e CRedBlackTreeNode. (eccetto m_value) sono destinati ad essere cambiati esclusivamente dalla classe della lista stessa. Nessun altro deve cambiarli. Ecco perché sono campi interni in dotnet. MQ ha creato dei metodi pubblici per modificare questi campi, e almeno gli avrebbero dato un nome specifico... ma no, solo i soliti nomi:

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

Ciao a tutti!

C'è un altro modo per eliminare gli elementi in CHashMap oltre a copiarli tramite CopyTo e cancellarli manualmente?

 

Ecco un paio di altre cose per affondare la fornace della scarsa implementazione della libreria. La loro classe CKeyValuePair eredita l'interfaccia IComparable (e quindi anche IEqualityComparable) per qualche ragione, richiedendo che il tipo utente Key supporti anche queste interfacce. Anche se non ce n'è bisogno se definiamo il nostro Comparer. In quello originale KeyValuePair non ha interfacce, ovviamente.

Se continuate a frugare, troverete cose ancora più strane:

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;
     }
  }

Cioè, se si passa accidentalmente un puntatore rotto nel costruttore, il programma non solo continuerà a lavorare in pace, ma cambierà anche la sua logica!

Il costruttore dovrebbe assomigliare a questo:

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)
{ }

E nessunPOINTER_INVALID . E c'è una firma diversa del costruttore per il comparatore di default.

 
C'è un esempio di come applicare correttamente un template CQueue<T> con una classe arbitraria come parametro T?
 
Già stato in un thread parallelo. Chiedete un divieto.
 

Puoi dirmi perché il codice non si compila?

#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

  }

Il problema è negli enum di sistema: ENUM_CHART_PROPERTY_DOUBLE, ENUM_CHART_PROPERTY_STRING c'è qualcosa che non va. Se uso il mio enum come tipo di chiave, anche la compilazione funziona.