Questions des débutants MQL5 MT5 MetaTrader 5 - page 1333

 
Mikhail Tkachev:

Merci pour la réponse, vous n'êtes pas maléfique du tout)
Maintenant tout a un sens)
UPD
Cette construction fonctionne aussi

Faites attention à ce que la méthode At() renvoie. Si elle renvoie NULL, vous vous écraserez sur une erreur critique. Avant d'accéder à un pointeur sur un objet, vérifiez qu'il n'est pas NULL.

 
Mikhail Tkachev:

Déjà remarqué)
La solution consiste donc à déclarer des objets globalement vides.....
Et si vous ne savez pas à l'avance combien il y en aura ? Il suffit de déclarer "avec réserve" :)
P.S. Je n'ai pas trouvé cette façon de déclarer des objets dans l'aide intégrée.

Il était une fois Artyom qui m'a écrit cette classe. Je ne peux pas expliquer en détail comment cela fonctionne. Mais Artem se souviendra et pourra expliquer. Voici la classe elle-même

#include <Arrays\ArrayObj.mqh>
/********************************************************************\
|   Класс Новый бар                                                  |
\********************************************************************/
class CNewBar : public CObject
  {
private:
  string            m_symbol;
  ENUM_TIMEFRAMES   m_timeframe;
  datetime          m_time;
  datetime          Time(void);                                       //  Возвращает время нулевого бара
  string            Symbol(void)         { return this.m_symbol;    }
public:
  ENUM_TIMEFRAMES   Timeframe(void)      { return this.m_timeframe; }
  datetime          GetTime(void)        { return this.m_time;      } //  Возвращает время последнего обращения
  bool              IsNewBar(void);                                   //  Основная функция класса

                    CNewBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
                   ~CNewBar(void){;}
  };
//+------------------------------------------------------------------+
//|    Конструктор                                                   |
//+------------------------------------------------------------------+
CNewBar::CNewBar(const string symbol,const ENUM_TIMEFRAMES timeframe) : m_time(0)
  {
   this.m_symbol = symbol;
   this.m_timeframe = (timeframe == PERIOD_CURRENT ? Period() : timeframe);
  }
//+------------------------------------------------------------------+
//| CNewBar Time Возвращает время нулевого бара                      |
//+------------------------------------------------------------------+
datetime CNewBar::Time(void)
  {
   datetime array[1], ret;
   ret = CopyTime(this.m_symbol, this.m_timeframe, 0, 1, array) == 1 ? array[0] : 0;
   return(array[0]);
  }
//+------------------------------------------------------------------+
//| CNewBar IsNewBar Основная функция класса                         |
//+------------------------------------------------------------------+
bool CNewBar::IsNewBar(void)
  {
   datetime tm = this.Time();
   if(tm == 0)
      return false;
   if(tm != this.m_time)
     {
      this.m_time = tm;
      return true;
     }
   return false;
  }

Et voici la boucle de création des pointeurs dans OnInit()

   for(int i = 0; i < ArraySize(Rates); i++)
     {
       CNewBar* nb = new CNewBar(Rates[i].m_Symbols, timefram);
       if(nb != NULL)
         {
          list_new_bar.Add(nb);
          Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
         }
     }

et dans OnTimer()

void OnTimer()
{
 int total = list_new_bar.Total();
 for(int i = 0; i < ArraySize(Rates); i++)
  {
   CNewBar* nb = list_new_bar.At(i);
   if(nb == NULL)
    continue;
   bool new_bar = nb.IsNewBar();
   if(new_bar)
    {// и дальше………

ArraySize(Rates) est la taille du tableau de structures dans lequel sont listés les caractères à travailler.

 
Alexey Viktorov:

Une fois, Artyom m'a écrit cette classe. Je ne peux pas expliquer en détail comment cela fonctionne. Mais Artyom s'en souviendra et sera capable de l'expliquer. Eh bien, voici la classe elle-même

Et voici la boucle de création des pointeurs dans OnInit()

et dans OnTimer()

ArraySize(Rates) est la taille du tableau de structures dans lequel sont listés les caractères à travailler.

Ici :

for(int i = 0; i < ArraySize(Rates); i++)

Je le ferais avant le total - simplement pour la raison que vous lisez les caractères du tableau Rates (n'est-ce pas ?), créez des instances de la nouvelle classe bar et les ajoutez à la liste.

En cas d'erreur d'addition, la taille de la liste des pointeurs vers les instances de la nouvelle classe de barres ne correspondra pas à la taille du tableau Rates.

En général, ça doit être quelque chose comme ça :

void OnTimer()
  {
   int total = list_new_bar.Total();
   for(int i = 0; i < total; i++)
   {
   CNewBar* nb = list_new_bar.At(i);
   if(nb == NULL)
      continue;
   if(nb.IsNewBar())
     {// и дальше………

Et c'est là que vous devez également vérifier si l'ajout à la liste est réussi :

   for(int i = 0; i < ArraySize(Rates); i++)
     {
       CNewBar* nb = new CNewBar(Rates[i].m_Symbols, timefram);
       if(nb != NULL)
         {
          list_new_bar.Add(nb);
          Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
         }
     }

quelque chose comme ça :

   for(int i = 0; i < ArraySize(Rates); i++)
     {
      CNewBar *nb = new CNewBar(Rates[i].m_Symbols, timefram);
      if(nb==NULL)
         continue;
      if(!list_new_bar.Add(nb))
        {
         delete nb;
         continue;
        }
      Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
     }
pour éviter les fuites de mémoire lorsqu'un pointeur vers un nouvel objet est ajouté par erreur à la liste
 
Artyom Trishkin:

Ici :

Je ferais avant le total - simplement pour la raison que vous lisez les caractères du tableau Rates (n'est-ce pas ?), créez des instances de la nouvelle classe bar et les ajoutez à la liste.

En cas d'erreur d'addition, la taille de la liste des pointeurs vers les instances de la nouvelle classe de barres ne correspondra pas à la taille du tableau Rates.

En général, ça doit être quelque chose comme ça :

Et c'est là que vous devez également vérifier si l'ajout à la liste est réussi :

quelque chose comme ça :

pour éviter les fuites de mémoire lorsqu'un pointeur vers un nouvel objet est ajouté par erreur à la liste

Merci. J'ai compris, je vais corriger comme ça :))))

Je déteste l'opérateur continue; et j'essaie de ne pas l'utiliser. Exclusivement dans les cas désespérés.

      if(nb==NULL)
         continue;

comment il diffère de

      if(nb!=NULL)
       {
       }
Une autre chose est qu'en cas d'erreur, le pointeur d'échec est supprimé... Mais même ici, nous pouvons nous passer de continue détesté ; simplement en supprimant Print(). C'était nécessaire pendant le débogage et pour essayer de comprendre ce qui se passe, et si pendant le travail une erreur se produit, je ne comprendrai pas ce qui ne va pas de toute façon... C'est plus facile de réinstaller l'OS que de comprendre les journaux.


Puisque nous sommes sur le sujet, dites-nous, sans entrer dans les détails, quelle est la différence entre un pointeur et une variable de classe, et laquelle est préférable. Je peux lire sur Internet des détails difficiles à comprendre. Une compréhension superficielle me suffit, pour ainsi dire...

 
Artyom Trishkin:

Faites attention à ce que la méthode At() renvoie. Si elle renvoie NULL, vous vous écraserez sur une erreur critique. Avant d'accéder à un pointeur sur un objet, vérifiez qu'il n'est pas NULL.

Artem, merci pour cette précieuse remarque ;)

 
Alexey Viktorov:

Merci. J'ai compris, je vais arranger ça comme ça... :)))

Je déteste l'opérateur continue; et j'essaie de ne pas l'utiliser. Exclusivement dans les cas désespérés.

En quoi il diffère de


L'itération de la boucle ne se terminera pas et n'en commencera pas une nouvelle, mais elle passera à l'itération suivante. La logique va changer.

 
Alexey Viktorov:

Une fois, Artyom m'a écrit cette classe. Je ne peux pas expliquer en détail comment cela fonctionne. Mais Artyom s'en souviendra et sera capable de l'expliquer. Bref, voici la classe elle-même

//+------------------------------------------------------------------+
//| CNewBar Time Возвращает время нулевого бара                      |
//+------------------------------------------------------------------+
datetime CNewBar::Time(void)
  {
   datetime array[1], ret;
   ret = CopyTime(this.m_symbol, this.m_timeframe, 0, 1, array) == 1 ? array[0] : 0;
   return(array[0]);
 }

Alexey, merci pour cette réponse si détaillée.
Le but de la variable ret dans le fragment de code cité n'est pas clair...
Dans quel but est-il calculé, si dans tous les cas la méthode renvoie array[0] ?
P.S.
Et pourquoi utiliser cette méthode dans une classe? Nous travaillons avec les membres de cette classe particulière...


 
Alexey Viktorov:

Merci. J'ai compris, je vais arranger ça comme ça... :)))

Je déteste l'opérateur continue; et j'essaie de ne pas l'utiliser. Exclusivement dans les cas désespérés.

comment il diffère de

Une autre chose est que, lorsqu'une erreur se produit, vous supprimez le pointeur d'échec... Mais même ici, vous pouvez vous passer de continue détesté ; supprimez simplement Print(). C'était nécessaire pendant le débogage et pour essayer de comprendre ce qui se passe, et si pendant le travail une erreur se produit, je ne comprendrai pas ce qui ne va pas de toute façon... Je préfère réinstaller l'OS que de comprendre les logs.


Puisque nous sommes sur le sujet, dites-nous, sans entrer dans les détails, quelle est la différence entre un pointeur et une variable de classe, et laquelle est préférable. Je peux lire sur Internet des détails difficiles à comprendre. Une compréhension superficielle me suffit, pour ainsi dire.

J'essaie de me débarrasser des parenthèses inutiles - pour ne pas faire de forêts et de branches. Sans l'impression, vous n'avez pas besoin de parenthèses - vous supprimez simplement l'objet.

Avec le nouvel opérateur, vous créez un mécanisme qui se trouve physiquement "quelque part". Le nouvel opérateur renvoie l'adresse de ce "quelque part". Et c'est la seule façon dont vous pouvez vous référer à ce "mécanisme".
Et le boulon à l'intérieur de ce mécanisme est une variable.
 
Valeriy Yastremskiy:

L'itération du cycle ne se terminera pas et n'en commencera pas une nouvelle, mais passera à la suivante. La logique va changer.

Effectue une transition vers une nouvelle itération du cycle, au sein de laquelle se trouve
 
Mikhail Tkachev:

Alexey, merci pour cette réponse si détaillée.
Le but de la variable ret dans le fragment de code donné n'est pas clair...
Pourquoi est-il calculé si la méthode renvoie de toute façon le tableau[0] ?


Alexey a retravaillé quelque chose dans le code que j'ai donné. Ou peut-être l'ai-je raté aussi - je l'ai écrit "à genoux" comme un simple exemple pour expliquer ce dont je ne me souviens plus.