Questions from Beginners MQL5 MT5 MetaTrader 5 - page 1333

 
Mikhail Tkachev:

Thanks for the reply, you're not evil at all)
Now it all makes sense)
UPD
This construction works too

Pay attention to what At() method returns. If it returns NULL, you will crash on critical error. Before accessing a pointer to an object, check it is not NULL

 
Mikhail Tkachev:

Already noticed)
So the solution is to declare globally empty objects....
And if you don't know beforehand how many of them there will be ? Just declare "with reserve" ? :)
P.S. I didn't find this way of declaring objects in the built-in help

Once upon a time Artyom wrote me this class. I can't explain in details how it works. But Artem will remember and will be able to explain. Here is the class itself

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

And here is the loop of creating pointers in 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());
         }
     }

and in 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) is the size of array of structures in which the characters to work with are listed.

 
Alexey Viktorov:

Artyom once wrote me this class. I can't explain in detail how it works. But Artyom will remember and will be able to explain. Well, here is the class itself

And here is the loop of creating pointers in OnInit()

and in OnTimer()

ArraySize(Rates) is the size of array of structures in which the characters to work with are listed.

Here:

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

I would do before total - simply for the reason that you're reading characters from the Rates array (right?), creating instances of the new bar class and adding them to the list.

On any addition error, the size of the list of pointers to instances of the new bar class will not match the size of the Rates array.

In general, it must be something like this:

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())
     {// и дальше………

And this is where you need to check for successful addition to the list too:

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

something like this:

   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());
     }
to avoid memory leaks when a pointer to a new object is added to the list by mistake
 
Artyom Trishkin:

Here:

I would do before total - simply for the reason that you read characters from the Rates array (right?), create instances of the new bar class and add them to the list.

On any addition error, the size of the list of pointers to instances of the new bar class will not match the size of the Rates array.

In general, it must be something like this:

And this is where you need to check for successful addition to the list too:

something like this:

to avoid memory leaks when a pointer to a new object is added to the list by mistake

Thanks. I got it, I'll correct it to this way:)))

I hate continue; operator and try not to use it. Exclusively in hopeless cases.

      if(nb==NULL)
         continue;

how it differs from

      if(nb!=NULL)
       {
       }
Another thing is if at error the failed pointer is deleted... But even here we can do without hated continue; simply by deleting Print(). It was needed during debugging and trying to understand what's going on, and if during work some error happens, I won't understand what's wrong anyway... It's easier to reinstall OS than to understand logs.


Since we're on the subject, please tell me, without getting into details, what is the difference between a pointer and a class variable, and which is preferable. I can read about it on the Internet in details that are difficult to understand. A superficial understanding is enough for me, so to speak...

 
Artyom Trishkin:

Pay attention to what the At() method returns. If it returns NULL, you will crash on critical error. Before accessing a pointer to an object, check it is not NULL.

Artem, thanks for the valuable comment)

 
Alexey Viktorov:

Thank you. I get it, I'll fix it like this... :)))

I hate the continue operator; and try not to use it. Exclusively in hopeless cases.

How it differs from


The loop iteration won't end and it won't start a new one, but it will move on to the next iteration. The logic will change.

 
Alexey Viktorov:

Artyom once wrote me this class. I can't explain in detail how it works. But Artyom will remember and will be able to explain. Anyway, here is the class itself

//+------------------------------------------------------------------+
//| 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, thank you for such a detailed reply.
The purpose of the ret variable in the cited code fragment is unclear...
What for is it calculated, if in any case method returns array[0] ?
P.S.
And why use this in a class method? We are working with members of this particular class...


 
Alexey Viktorov:

Thank you. I get it, I'll fix it like this... :)))

I hate the continue operator; and try not to use it. Exclusively in hopeless cases.

how it differs from

Another thing is if, when an error occurs, you delete the failed pointer... But even here you can do without hated continue; just delete Print(). It was needed during debugging and trying to understand what's going on, and if during work some error happens, I won't understand what's wrong anyway... I'd rather reinstall OS than understand logs.


Since we're on the subject, please tell us, without getting into details, what is the difference between a pointer and a class variable, and which is preferable. I can read about it on the Internet in details that are difficult to understand. A superficial understanding is enough for me, so to say.

I'm trying to get rid of unnecessary brackets - so I don't make forests and branches. Without the print there is no need for brackets - just delete the object.

With the new operator you create some mechanism that physically lies "somewhere". The new operator returns the address of this "somewhere". And that's the only way you can refer to this "mechanism".
And the bolt inside that mechanism is a variable.
 
Valeriy Yastremskiy:

The iteration of the cycle will not end and it will not start a new one, but will move on to the next If. The logic will change.

Makes a transition to a new iteration of the cycle, within which is
 
Mikhail Tkachev:

Alexey, thank you for such a detailed answer.
The purpose of ret variable in the given code fragment is not clear...
Why is it calculated if the method returns array[0] anyway?


Alexey reworked something in the code I gave. Or maybe I missed it too - I wrote it "on my knees" as a simple example to explain what I don't remember anymore.
Reason: