Bibliothèque de classes génériques - bogues, description, questions, caractéristiques d'utilisation et suggestions - page 29

 
Alexey Volchanskiy:

MSDN appelle cela un tampon circulaire, je n'ai pas trouvé ce nom.

lien vers le

Alexey Navoykov:

...et se terminant par une conversion des arguments par référence, et non plus seulement par valeur.

il peut y avoir un problème avec les littéraux

 
TheXpert:

lien dans le studio.

Il peut y avoir un problème avec les littéraux

J'ai la flemme de chercher à nouveau cet article, mais je l'ai un peu étiré. Une liste liée simple ou double en anneau est basée sur une liste liée, mais le dernier élément stocke un lien vers le tout premier élément.

 
TheXpert:

il peut y avoir des problèmes avec les littéraux

Non, la classe "values" est héritée de la classe de base "reference", purement en tant qu'enveloppe. Il suffit donc de sélectionner la version de la classe souhaitée - et d'y aller.
 
Alexey Volchanskiy:

Une liste liée simple ou double est basée sur une liste liée, mais le dernier élément de la liste liée stocke un lien vers le tout premier élément.

C'est là le problème : il s'agit d'un conteneur "de base", pas d'un conteneur de remplacement. Personne n'a empêché les développeurs d'en faire un conteneur supplémentaire ici aussi. Au lieu de substituer des concepts communs
 
Alexey Navoykov:

Il est probable que celui qui a porté ces classes a simplement décidé de se simplifier la vie en simplifiant le code. Au lieu de deux pointeurs m_first et m_last, il a fait un pointeur m_head...

J'ai regardé les sources dotnet, et j'ai compris la raison. La classe LinkedList elle-même est portée correctement, il n'y a vraiment qu'une tête de pointeur, qui est à la fois le début et la fin. L'implémentation interne est donc bien bouclée, mais le comportement externe ne l'est pas. MQ a une erreur dans la classe CLinkedNode (méthodes Next et Previous). Voici à quoi ressemble leur implémentation 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; }
        }

Et voici comment il est porté sur MQL :

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

Peut-être qu'ils étaient inattentifs et se sont trompés.

Mais en général, je suis aussi un peu surpris de l'implémentation de dotnet. Pourquoi n'était-il pas possible de faire deux pointeurs dans la liste elle-même (premier et dernier) au lieu d'une tête. Cela éviterait des vérifications supplémentaires dans les méthodes ci-dessus de la liste de nœuds, c'est-à-dire qu'elles ressembleraient exactement à la MQ actuelle, mais tout fonctionnerait correctement. Bien sûr, cela ralentirait le processus d'insertion/suppression de nœuds, mais cela accélérerait l'itération sur eux, ce qui est une priorité beaucoup plus élevée. Next et Previous sont définitivement appelés plus souvent que les nœuds ajoutés. C'est comme ça que j'ai fait, je pensais qu'il en serait de même pour melkomsoft. Mais tant pis ;)

A propos, MQ a un autre bug dans l'implémentation de CLinkedListNode et CRedBlackTreeNode. (sauf m_value) sont destinés à être modifiés exclusivement par la classe de liste elle-même. Personne d'autre ne doit les modifier. C'est pourquoi il s'agit de champs internes dans dotnet. MQ a rendu publiques des méthodes pour changer ces champs, et au moins ils les auraient nommés spécifiquement... mais non, juste les noms habituels :

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

Bonjour à tous !

Existe-t-il un autre moyen de supprimer des éléments dans CHashMap que de les copier via CopyTo et de les supprimer manuellement ?

 

Voici quelques autres choses pour enfoncer la fournaise de la mauvaise implémentation de la bibliothèque. Leur classe CKeyValuePair hérite de l'interface IComparable (et donc IEqualityComparable aussi) pour une raison quelconque, exigeant que le type utilisateur Key supporte aussi ces interfaces. Bien qu'il n'y ait pas besoin de cela si nous définissons notre propre Comparer. Dans l'original KeyValuePair n'a pas d'interfaces bien sûr.

Si tu continues à fouiller, tu trouveras des choses encore plus étranges :

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

C'est-à-dire que si vous passez accidentellement un pointeur cassé dans le constructeur, non seulement le programme continuera à fonctionner en paix, mais sa logique changera aussi !

Le constructeur devrait ressembler à ceci :

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

Et pas dePOINTER_INVALID . Et il y a une signature de constructeur différente pour le comparateur par défaut.

 
Existe-t-il un exemple permettant d'appliquer correctement un modèle de CQueue<T> avec une classe arbitraire comme paramètre T ?
 
Déjà vu dans un fil parallèle. Demandez une interdiction.
 

Pouvez-vous me dire pourquoi le code ne se compile pas ?

#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

  }

Le problème se situe dans les enums du système : ENUM_CHART_PROPERTY_DOUBLE, ENUM_CHART_PROPERTY_STRING ; quelque chose ne va pas avec eux. Si j'utilise mon propre enum comme type de clé, la compilation fonctionne également.