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

 
Andrey Pogoreltsev:

Vous créez des copies d'objets dans AddValue via new, mais vous ne les libérez pas dans le destructeur, vous effacez simplement la liste des pointeurs.

L'aide indique que l'appel d'un destructeur appelle également les destructeurs des classes que vous avez utilisées.

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

Je ne me souviens pas d'un cas où le terminal n'a pas écrit dans le journal un avertissement concernant les objets non détruits après le déchargement du script - mon exemple ne montre pas un tel avertissement.


Andrey Pogoreltsev:

Deuxièmement, vous auriez dû le faire correctement avec le constructeur de copie au lieu de l'opérateur d'affectation. Mais tout ceci est IMHO).

J'ai trouvé des informations de la part de développeurs selon lesquelles les structures ou les classes simples en MQL sont toujours copiées sans aucun problème, je l'ai vérifié plusieurs fois et cela semble être vrai, pour autant que j'utilise les fonctionnalités du langage.


C'est sur ce point que porte la discussion - MQL n'est pas C++, j'ai arrêté de chercher des analogies entre les deux, les développeurs ont écrit que c'est ainsi qu'il est implémenté - je l'ai vérifié, cela fonctionne - donc vous pouvez l'utiliser, si la syntaxe standard C++ est cruciale, vous pouvez facilement écrire toute la logique en .dll.

Документация по MQL5: Стандартная библиотека / Коллекции данных / CArrayObj
Документация по MQL5: Стандартная библиотека / Коллекции данных / CArrayObj
  • www.mql5.com
Класс CArrayObj обеспечивает возможность работы с динамическим массивом указателей на экземпляры класса CObject и его наследников. Это дает возможность работы как с многомерными динамическими массивами примитивных типов данных, так и с более сложно организованными структурами данных. В классе реализованы возможности добавления/вставки/удаления...
 
Andrey Pogoreltsev:

Vous créez des copies d'objets dans AddValue via new, mais vous ne les libérez pas dans le destructeur, vous effacez simplement la liste des pointeurs.

Oh, mon Dieu ! Et comment supprimer une instance d'une classe créée via new dans le destructeur. Essayez de le faire. Cela ne fonctionnera pas.

Vous ne pouvez le faire que dans le destructeur d'une autre classe.

 
Nikolai Semko:

Oh, merde ! Et comment supprimer une instance d'une classe créée via new dans le destructeur. Vous pouvez l'essayer. Cela ne fonctionnera pas.

Vous ne pouvez le faire que dans le destructeur d'une autre classe.

Je parlais du destructeur d'une autre classe. Je parlais des éléments créés par new dans la méthodeAddValue.

 
Igor Makanu:

L'aide indique que lorsque le destructeur est appelé, les destructeurs des classes utilisées seront également appelés.

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

Je ne me souviens pas d'un cas où le terminal n'a pas écrit un avertissement sur les objets non détruits dans le journal après le déchargement du script - mon exemple ne montre pas un tel avertissement.


j'ai entendu dire par les développeurs que les structures ou classes simples en MQL sont toujours copiées sans aucun problème, je l'ai vérifié plusieurs fois et cela semble être vrai, jusqu'à présent j'utilise les possibilités du langage


C'est sur ce point que porte la discussion - MQL n'est pas C++, j'ai arrêté de chercher des analogies entre les deux, les développeurs ont écrit que c'est ainsi qu'il est implémenté - je l'ai vérifié, cela fonctionne - donc vous pouvez l'utiliser, si la syntaxe standard C++ est cruciale, je ne devrais pas avoir à m'inquiéter de mettre toute la logique dans une .dll.

Oui, je l'ai vu dans l'aide... Très implicite, cela ressemble plus à une béquille, au lieu de unique_ptr...

 
Andrey Pogoreltsev:

Oui, je l'ai vu dans l'aide... Chose très implicite, plutôt comme une béquille à la place de unique_ptr...

Et c'est tellement pratique que je ne peux même pas appeler ça une béquille :

Créez un objet de n'importe quelle classe, placez-le dans une liste de stockage, et vous n'avez plus à vous soucier de le supprimer - le sous-système du terminal le nettoie de lui-même.
Mais vous pouvez également définir une opération manuelle et "exécuter" pour tous les objets nouvellement créés en essayant de savoir quand, où et dans quel but ils ont été créés et s'ils sont nécessaires maintenant. S'il n'est pas nécessaire, supprimez-le. Mais lorsque vous avez fait une erreur, il s'avère que c'était nécessaire - il se plante en accédant à un pointeur invalide...

La béquille consiste donc à "chasser les objets" en recherchant leur inutilité et en s'inquiétant des fuites de mémoire si un objet n'a pas été rattrapé.

 
Andrey Pogoreltsev:

Deuxièmement, la bonne chose à faire est d'utiliser le constructeur de copie au lieu de l'opérateur d'affectation. Mais c'est tout IMHO)

Pouvez-vous me donner un exemple de la façon de le copier correctement pour ce modèle ?

template<typename T>class CDataBase
  {
private:
   CList            *mlist;
   T                *Tptr;
public:
   void CDataBase()           { mlist=new CList;                                       }
   void ~CDataBase(void)      { delete mlist;                                          }
   int ArraySize(void)        { return(mlist.Total());                                 }
   T *operator[](int index)   { return(mlist.GetNodeAtIndex(index));                   }
   void  AddValue (T &value)  { Tptr = new T; Tptr  = value; mlist.Add(Tptr);          }
   string TypeName()          { return(typename(T));                                   }
  };

J'ai utilisé l'aide pour écrire la méthode AddValuehttps://www.mql5.com/ru/docs/basis/types/classes.

Je me suis creusé la tête, mais je ne vois pas d'autre solution dans MQL que celle que j'ai écrite dans mon exemple !

Montrez-moi votre mise en œuvre d'un stockage correct des données

Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
  • www.mql5.com
Структура является набором элементов произвольного типа (кроме типа void). Таким образом, структура объединяет логически связанные данные разных типов. Объявление структуры Имя структуры нельзя использовать в качестве идентификатора (имени переменной или функции). Следует иметь ввиду, что в MQL5 элементы структуры следуют непосредственно друг...
 
Artyom Trishkin:

Et c'est tellement pratique qu'on ne peut même pas appeler ça une béquille :

Créez n'importe quel objet de n'importe quelle classe, placez-le dans la liste de stockage, et vous n'avez plus à vous soucier de le supprimer - le sous-système terminal le nettoie de lui-même.
Mais vous pouvez également paramétrer une opération manuelle et "exécuter" tous les objets nouvellement créés en essayant de savoir quand, où et dans quel but ils ont été créés et s'ils sont nécessaires maintenant. S'il n'est pas nécessaire, supprimez-le. Mais lorsque vous avez fait une erreur, il s'avère que c'était nécessaire - il se plante en accédant à un pointeur invalide...

La béquille consiste donc à "chasser les objets" en recherchant leur inutilité et en s'inquiétant des fuites de mémoire si un objet n'a pas été rattrapé.

Ce que je veux dire ici, c'est que lorsque vous ajoutez un pointeur à la collection, il reste également avec vous. C'est la première chose.

Deuxièmement, nous ne parlons pas de tableaux-collections et de lecture continue ; vous avez un système fragmenté.

Troisièmement, vous ne pouvez pas garantir que vous avez transmis un pointeur vers un objet de collection.
 
Andrey Pogoreltsev:
L'idée est qu'une fois que vous ajoutez un pointeur à la collection, il reste également avec vous. C'est le premier.

Deuxièmement, nous ne parlons pas de tableaux-collections et de lecture continue ; vous avez un système fragmenté.

Troisièmement, personne ne garantit que vous avez transmis un pointeur à l'objet de la collection.
  1. Je voulais dire que vous appelez béquille la suppression automatique par le sous-système terminal de tous vos objets créés et de mettre des pointeurs vers eux dans des listes, et que vous ne considérez pas comme une béquille la manipulation manuelle de vos objets et la création de béquilles pour celle-ci.
  2. Cela ne faisait pas partie de ce que vous avez dit au point 1, et c'est la raison principale de ma réponse.
  3. Cela aussi, et pour la même raison.
 
Igor Makanu:

L'aide indique que lorsque le destructeur est appelé, les destructeurs des classes utilisées seront également appelés.

https://www.mql5.com/ru/docs/standardlibrary/datastructures/carrayobj#carrayobjfeatures

Je ne me souviens pas d'un cas où le terminal n'a pas écrit un avertissement sur les objets non détruits dans le journal après le déchargement du script - mon exemple ne montre pas un tel avertissement.


j'ai entendu dire par les développeurs que les structures ou classes simples en MQL sont toujours copiées sans aucun problème, je l'ai vérifié plusieurs fois et cela semble être vrai, jusqu'à présent j'utilise les possibilités du langage


C'est sur ce point que porte la discussion - MQL n'est pas C++, j'ai renoncé à chercher des analogies entre les deux, les développeurs ont écrit que c'est ainsi qu'il est implémenté - je l'ai vérifié, cela fonctionne - donc vous pouvez l'utiliser, si la syntaxe standard C++ est cruciale, vous pouvez facilement écrire toute la logique en .dll.

Peut-on faire un réseau triangulaire avec ça ?

 

En raison des limitations linguistiques, il est peu probable que quelque chose de décent fonctionne. J'ai cette béquille (une enveloppe légère sur un tableau standard).

#define  GENERATE_VECTOR_GROWTH_FACTOR 2
#define  GENERATE_VECTOR(NAME, REF)                                         \  
   template <typename T>                                                   \
   class NAME                                                              \
   {                                                                       \
      int sz;                                                              \
      bool fail_state;                                                     \
   public:                                                                 \
      T a[];                                                               \
      NAME(): sz(0), fail_state(false) {}                                  \
      bool operator!()const      {return this.fail_state;}                 \
      uint size()const           {return this.sz;}                         \
      void clear()               {this.sz = 0; this.fail_state = false;}   \
      void push_back(T REF value) {                                        \
         if (this.sz == ArraySize(this.a)  &&                              \
             ArrayResize(this.a, this.sz*                                  \
                           GENERATE_VECTOR_GROWTH_FACTOR+1) == -1) {       \
            this.fail_state = true;                                        \
            return;                                                        \
         }                                                                 \
         this.a[this.sz++] = value;                                        \
      }                                                                    \
      void reserve(int new_cap) {                                          \
         if (new_cap > ArraySize(this.a))                                  \
            ArrayResize(this.a, new_cap);                                  \
      }                                                                    \
      void erase(int pos) {                                                \
         if ( ! ArrayRemove(this.a, pos, 1) )                              \
            this.fail_state = true;                                        \
      }                                                                    \
   };
#define  GENERATE_VECTOR_EMPTY
GENERATE_VECTOR(vector_fund, GENERATE_VECTOR_EMPTY);  // для фундаментальных типов
GENERATE_VECTOR(vector_ref, const &);                 // для пользовательских
#undef  GENERATE_VECTOR_EMPTY
#undef  GENERATE_VECTOR_GROWTH_FACTOR

struct S {int a;};
class Q {};
bool f() {
   vector_ref<S> v1;
   vector_fund<int> v2;
   vector_ref<Q> v3;
   
   Q q;
   v3.push_back(q);
   v2.push_back(3);
   v2.a[0] = 5;
   
   return !(!v1 || !v2 || !v3);
}

Pour stocker des pointeurs, écrivez un wrapper unic_ptr (bien que vous ne puissiez pas en obtenir un complet, mais au moins auto_ptr). À mon avis, même une telle primitive est beaucoup plus pratique que les contreparties des modèles de std.