Preguntas de los principiantes MQL5 MT5 MetaTrader 5 - página 1333

 
Mikhail Tkachev:

Gracias por la respuesta, no eres nada malo)
Ahora todo tiene sentido)
UPD
Esta construcción también funciona

Preste atención a lo que devuelve el método At(). Si devuelve NULL, se estrellará por un error crítico. Antes de acceder a un puntero a un objeto, comprueba que no es NULL

 
Mikhail Tkachev:

Ya lo he notado)
Así que la solución es declarar objetos globalmente vacíos....
¿Y si no se sabe de antemano cuántos serán? ¿Sólo declarar "con reserva"? :)
P.D. No encontré esta forma de declarar objetos en la ayuda incorporada

Una vez Artyom me escribió esta clase. No puedo explicar en detalle cómo funciona. Pero Artem lo recordará y podrá explicarlo. Aquí está la clase en 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;
  }

Y aquí está el bucle de creación de punteros en 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());
         }
     }

y en 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) es el tamaño del array de estructuras en el que se encuentran los caracteres con los que se va a trabajar.

 
Alexey Viktorov:

Artyom me escribió una vez esta clase. No puedo explicar en detalle cómo funciona. Pero Artyom lo recordará y podrá explicarlo. Aquí está la clase en sí

Y aquí está el bucle de creación de punteros en OnInit()

y en OnTimer()

ArraySize(Rates) es el tamaño del array de estructuras donde se listan los caracteres a trabajar.

Aquí:

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

Yo lo haría antes que el total - simplemente por la razón de que estás leyendo caracteres del array Rates (¿verdad?), creando instancias de la nueva clase de barra y añadiéndolas a la lista.

En cualquier error de adición, el tamaño de la lista de punteros a instancias de la nueva clase de barra no coincidirá con el tamaño del array Rates.

En general, debe ser algo así:

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

Y aquí es donde también hay que comprobar si se ha añadido con éxito a la lista:

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

algo así:

   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());
     }
para evitar pérdidas de memoria cuando se añade por error un puntero a un nuevo objeto a la lista
 
Artyom Trishkin:

Aquí:

Yo lo haría antes que el total - simplemente por la razón de que se leen los caracteres del array Rates (¿no?), se crean instancias de la nueva clase bar y se añaden a la lista.

En cualquier error de adición, el tamaño de la lista de punteros a instancias de la nueva clase de barra no coincidirá con el tamaño del array Rates.

En general, debe ser algo así:

Y aquí es donde también hay que comprobar si se ha añadido con éxito a la lista:

algo así:

para evitar pérdidas de memoria cuando se añade por error un puntero a un nuevo objeto a la lista

Gracias. Lo tengo, lo corregiré de esta manera:)))

Odio continuar; operador y trato de no usarlo. Exclusivamente en casos desesperados.

      if(nb==NULL)
         continue;

en qué se diferencia de

      if(nb!=NULL)
       {
       }
Otra cosa es que en caso de error se borre el puntero fallido... Pero incluso aquí podemos prescindir de hated continue; simplemente borrando Print(). Era necesario durante la depuración y tratar de entender lo que está pasando, y si durante el trabajo se produce algún error, no voy a entender lo que está mal de todos modos ... Es más fácil volver a instalar el sistema operativo que entender los registros.


Ya que estamos en el tema, dinos, sin entrar en detalles, cuál es la diferencia entre un puntero y una variable de clase, y cuál es preferible. Puedo leer sobre ello en Internet con detalles difíciles de entender. Me basta con una comprensión superficial, por así decirlo...

 
Artyom Trishkin:

Preste atención a lo que devuelve el método At(). Si devuelve NULL, se estrellará por un error crítico. Antes de acceder a un puntero a un objeto, comprueba que no es NULL.

Artem, gracias por el valioso comentario)

 
Alexey Viktorov:

Gracias. Lo entiendo, lo arreglaré así... :)))

Odio el operador continue; e intento no usarlo. Exclusivamente en casos desesperados.

En qué se diferencia de


La iteración del bucle no terminará ni comenzará una nueva, sino que pasará a la siguiente iteración. La lógica cambiará.

 
Alexey Viktorov:

Artyom me escribió una vez esta clase. No puedo explicar en detalle cómo funciona. Pero Artyom lo recordará y podrá explicarlo. De todos modos, aquí está la clase en sí

//+------------------------------------------------------------------+
//| 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, gracias por una respuesta tan detallada.
El propósito de la variable ret en el fragmento de código citado no está claro...
¿Para qué se calcula, si en algún caso el método devuelve array[0]?
P.D.
¿Y por qué usar esto en un método de clase? Estamos trabajando con miembros de esta clase particular...


 
Alexey Viktorov:

Gracias. Lo entiendo, lo arreglaré así... :)))

Odio el operador continue; e intento no usarlo. Exclusivamente en casos desesperados.

en qué se diferencia de

Otra cosa es que, cuando se produzca un error, se borre el puntero fallido... Pero aquí también se puede prescindir de hated continue; basta con borrar Print(). Era necesario durante la depuración y tratar de entender lo que está pasando, y si durante el trabajo se produce algún error, no voy a entender lo que está mal de todos modos ... Prefiero reinstalar el sistema operativo que entender los registros.


Ya que estamos en el tema, dinos, sin entrar en detalles, cuál es la diferencia entre un puntero y una variable de clase, y cuál es preferible. Puedo leer sobre ello en Internet con detalles difíciles de entender. A mí me basta con una comprensión superficial, por así decirlo.

Estoy tratando de deshacerme de los paréntesis innecesarios, para no hacer bosques y ramas. Sin la impresión no hay necesidad de paréntesis - sólo eliminar el objeto.

Con el nuevo operador se crea un mecanismo que se encuentra físicamente "en algún lugar". El nuevo operador devuelve la dirección de este "algún lugar". Y esa es la única forma de referirse a este "mecanismo".
Y el cerrojo dentro de ese mecanismo es una variable.
 
Valeriy Yastremskiy:

La iteración del ciclo no terminará y no comenzará una nueva, sino que pasará al siguiente Si. La lógica cambiará.

Hace una transición a una nueva iteración del ciclo, dentro de la cual es
 
Mikhail Tkachev:

Alexey, gracias por una respuesta tan detallada.
El propósito de la variable ret en el fragmento de código dado no está claro...
¿Por qué se calcula si el método devuelve array[0] de todos modos?


Alexey ha modificado algo en el código que le di. O tal vez yo también me lo perdí, lo escribí "de rodillas" como un simple ejemplo para explicar lo que ya no recuerdo.
Razón de la queja: