Вопросы от начинающих MQL5 MT5 MetaTrader 5 - страница 1333

 
Mikhail Tkachev:

Спасибо за ответ, вовсе вы не злой)
Теперь все стало ясно)
UPD
Вот такая конструкция тоже работает

Обратите внимание на то, что возвращает метод At(). Если вернёт NULL, то вылетите по критической ошибке. Прежде, чем обращаться по указателю к объекту, проверьте его на не NULL

 
Mikhail Tkachev:

Уже заметил)
Значит, выход - объявлять глобально пустые объекты....
А если заранее неизвестно, сколько их будет ? Просто объявить "с запасом"  ?  :)
P.S. Во встроенной справке не нашел такой способ объявления объектов 

Когда-то Артём писал мне этот класс. Я в подробностях объяснить как работает не могу. Но Артём увидев вспомнит и сможет объяснить. В общем вот сам класс

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

И вот цикл создания указателей в 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());
         }
     }

и в 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) это размер массива структур в котором перечислены символы с которыми надо работать.

 
Alexey Viktorov:

Когда-то Артём писал мне этот класс. Я в подробностях объяснить как работает не могу. Но Артём увидев вспомнит и сможет объяснить. В общем вот сам класс

И вот цикл создания указателей в OnInit()

и в OnTimer()

ArraySize(Rates) это размер массива структур в котором перечислены символы с которыми надо работать.

Здесь:

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

я бы делал до total - просто по причине, что ты с массива Rates читаешь символы (верно?), создаёшь экземпляры класса нового бара и добавляешь их в список.

При любой ошибке добавления, размер списка указателей на экземпляры класса нового бара не будет совпадать с размером массива Rates.

В общем, как-то так наверное:

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

А вот тут нужно тоже проверять на успешность добавления в список:

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

как-то так:

   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());
     }
во избежание утечки памяти при ошибке добавления указателя на новый объект в список
 
Artyom Trishkin:

Здесь:

я бы делал до total - просто по причине, что ты с массива Rates читаешь символы (верно?), создаёшь экземпляры класса нового бара и добавляешь их в список.

При любой ошибке добавления, размер списка указателей на экземпляры класса нового бара не будет совпадать с размером массива Rates.

В общем, как-то так наверное:

А вот тут нужно тоже проверять на успешность добавления в список:

как-то так:

во избежание утечки памяти при ошибке добавления указателя на новый объект в список

Спасибо. Я понял, исправлю на так…:)))

Ненавижу оператор continue; и стараюсь им не пользоваться. Исключительно в безвыходных случаях.

      if(nb==NULL)
         continue;

чем отличается от

      if(nb!=NULL)
       {
       }
Другое дело если при ошибке удалить несостоявшийся указатель… Но и тут можно обойтись без ненавистного мне continue; просто удалив Print(). Он был нужен во время отладки и попытки понять происходящее, а если во время работы произойдёт какая-то ошибка, я по любому не пойму что не так… Мне проще переустановить ОС, чем разобраться в логах.


Раз уж пошёл разговор об этом, расскажи пожалуйста, только не влезая в дебри, чем отличается указатель от переменной класса и что предпочтительней. В подробностях, в таких которые понять сложно я могу в тырнете почитать. Мне достаточно, так сказать, поверхностного понимания…

 
Artyom Trishkin:

Обратите внимание на то, что возвращает метод At(). Если вернёт NULL, то вылетите по критической ошибке. Прежде, чем обращаться по указателю к объекту, проверьте его на не NULL

Артем, спасибо за ценное замечание)

 
Alexey Viktorov:

Спасибо. Я понял, исправлю на так…:)))

Ненавижу оператор continue; и стараюсь им не пользоваться. Исключительно в безвыходных случаях.

чем отличается от


Итерацию цикла не закончит и новую не начнет, а перейдет к следующему Иф. Логика поменяется.

 
Alexey Viktorov:

Когда-то Артём писал мне этот класс. Я в подробностях объяснить как работает не могу. Но Артём увидев вспомнит и сможет объяснить. В общем вот сам класс

//+------------------------------------------------------------------+
//| 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]);
 }

Алексей, спасибо за столь развернутый ответ.
В приведенном фрагменте кода непонятно назначение переменной ret...
Для чего она вычисляется, если в любом случае метод возвращает array[0] ?
З.Ы.
А для чего в методе класса использовать this ? Мы ведь работает с членами этого конкретного класса...


 
Alexey Viktorov:

Спасибо. Я понял, исправлю на так…:)))

Ненавижу оператор continue; и стараюсь им не пользоваться. Исключительно в безвыходных случаях.

чем отличается от

Другое дело если при ошибке удалить несостоявшийся указатель… Но и тут можно обойтись без ненавистного мне continue; просто удалив Print(). Он был нужен во время отладки и попытки понять происходящее, а если во время работы произойдёт какая-то ошибка, я по любому не пойму что не так… Мне проще переустановить ОС, чем разобраться в логах.


Раз уж пошёл разговор об этом, расскажи пожалуйста, только не влезая в дебри, чем отличается указатель от переменной класса и что предпочтительней. В подробностях, в таких которые понять сложно я могу в тырнете почитать. Мне достаточно, так сказать, поверхностного понимания…

Я стараюсь избавиться от лишних скобок - чтобы не городить лесенок и ветвлений. Без принта там и скобки не нужны - останется просто удаление объекта.

По оператору new ты создаёшь некий механизм, который физически лежит "где-то". Оператор new возвращает адрес этого "где-то". И только по нему ты можешь обратиться именно к этому "механизму".
А болтик внутри этого механизма - это переменная.
 
Valeriy Yastremskiy:

Итерацию цикла не закончит и новую не начнет, а перейдет к следующему Иф. Логика поменяется.

Осуществляет переход на новую итерацию цикла, внутри которого находится
 
Mikhail Tkachev:

Алексей, спасибо за столь развернутый ответ.
В приведенном фрагменте кода непонятно назначение переменной ret...
Для чего она вычисляется, если в любом случае метод возвращает array[0] ?


Это Алексей что-то переделывал в том коде, который я давал. А может и я недоглядел - писал "на коленке" в качестве простого примера для пояснения уже не помню чего.
Причина обращения: