Características del lenguaje mql5, sutilezas y técnicas - página 130

 
// ArrayResize с освобождением памяти
template <typename T>
int ArrayResize2( T &Array[], const int NewSize, const int Reserve = 0 )
{
  T ArrayTmp[];
  
  ArraySwap(Array, ArrayTmp);
  const int Res = ArrayResize(Array, NewSize, Reserve);
  
  if (Res > 0)
    ArrayCopy(Array, ArrayTmp, 0, 0, MathMin(Res, ArraySize(ArrayTmp)));
    
  return(Res);
}
 
fxsaber:

Gracias. Utilizar la función ArraySwap no se me habría ocurrido.

Entiendo que su función funcionará tanto al aumentar como al disminuir el tamaño, es decir, como un análogo completo de ArrayResize.

¿No es mejor llamar simplemente a la función estándar ArrayResize cuando se amplía un array, en lugar de llamar a las tres funcionesArraySwap,ArrayResize,ArrayCopy?


p.s He probado tu versión y la mía con dos copias al reducir el array MqlTick de 1.000.000 a 500.0000. Su versión lo hace en 22 milésimas de segundo. El mío lo hace en 37-38.
 
pivomoe:

¿No es mejor llamar simplemente a la función estándar ArrayResize cuando se amplía un array que llamar a tres funcionesArraySwap,ArrayResize,ArrayCopy

Lo pensé, pero no lo hice, porque en realidad hay más sutilezas. Por eso decidí quedarme con la versión lacónica.

Una de las sutilezas es esta. Si tomas un array de estructuras con constructores/destructores, ArrayResize los llamará en cualquier dirección en una cantidad igual a la diferencia de valores.

Pero aplicar ArrayCopy es llamar a todos los constructores. La eliminación de ArrayTmp es una llamada a todos los destructores. Así que ArrayResize2 no es realmente ArrayResize.

 
Resulta que se puede escribir ArrayResize( arr, new_size, -1) así. Pero tu versión sigue siendo más rápida, unos 22 frente a 37 milisegundos.
 
Puede ocurrir que salgas del modo marco del EA y necesites volver a entrar en él. El siguiente Asesor Experto muestra cómo hacerlo
// Создание mqd-Файла из Тестера, чтение mqd-файла из Терминала во фрейм/стандартном режиме работы советника.

input int Range = 0; // 0..10

void OnTesterInit( void ) {}
void OnTesterDeinit( void ) {}

#define  TOSTRING(A) #A + " = " + (string)(A) + " "

void OnTesterPass( void )
{
  ulong Pass;
  string Name;
  long ID;
  double Value;

  while (FrameNext(Pass, Name, ID, Value)) // Прочли очередной проход из mqd-файла.
    Print(TOSTRING(Pass) + TOSTRING(Name) + TOSTRING(Value)); // Вывели данные mqd-файла
}

double OnTester( void )
{
  if (MQLInfoInteger(MQL_OPTIMIZATION))
  {
    uchar Data[];

    FrameAdd(TerminalInfoString(TERMINAL_DATA_PATH), 0, MathRand(), Data); // Отправили данные в mqd-файл Терминала.
  }

  return(0);
}

void OnInit()
{
  if (MQLInfoInteger(MQL_TESTER))
  {
    // OnInit для Тестера
  }
  else if (FrameFirst()) // Удалось инициализировать mqd-файл.
  {
    OnTesterInit();
    OnTesterPass();
  }
}

void OnDeinit( const int )
{
  if (MQLInfoInteger(MQL_TESTER))
  {
    // OnDeinit для Тестера
  }
  else
    OnTesterDeinit();
}

void OnTick()
{
  static const bool IsTester = MQLInfoInteger(MQL_TESTER);
  
  if (!IsTester)
    return;
    
  // OnTick для Тестера.
}


Tras la optimización, verá lo siguiente

Pass = 0 Value = 25534.0 
Pass = 1 Value = 12915.0 
Pass = 7 Value = 25534.0 
Pass = 8 Value = 12915.0 
Pass = 6 Value = 6528.0 
Pass = 5 Value = 2523.0 
Pass = 3 Value = 22229.0 
Pass = 2 Value = 9767.0 
Pass = 4 Value = 7748.0 
Pass = 9 Value = 25534.0 
Pass = 10 Value = 12915.0 


Si desactiva el Asesor Experto en modo marco y lo ejecuta en modo estándar, mostrará los mismos datos que obtuvo durante la optimización.

Este enfoque le permite volver a los resultados de la optimización muchas veces.


SZY En el gráfico que se abre en la Terminal para el modo frame, no se puede ejecutar ningún Asesor Experto. Por lo tanto, si desea ejecutarlo en modo estándar, deberá hacerlo en un gráfico que no haya sido abierto por marcos.

 
extern es ahora una macro codificada
#undef extern
#define extern // macro redefinition
En consecuencia, no siempre será posible hacer que el código de MT5 mq4 funcione sin cambios.
 

fxsaber:
extern теперь является жестко заданным макросом

En consecuencia, no siempre será posible hacer que el código de MT5 mq4 funcione sin cambios.

No hay cambios en la documentación. ¿Puede explicar esto con más detalle?

 
Alexey Viktorov:

No hay ningún cambio en la documentación. ¿Puede explicar esto con más detalle?

Dicho código

#property script_show_inputs

#define extern input // macro redefinition

extern int i = 0;

void OnStart() {}

siempre generará una advertencia. Estoy siendo un poco duro con lo de "imposible". Es posible anularlo, por lo que siempre se colgará un aviso en estas situaciones.

 
fxsaber:

Uno de los matices es este. Si tomas un array de estructuras con constructores/destructores, entonces ArrayResize en cualquier dirección los llama en un número igual a la diferencia de valores.

Pero aplicar ArrayCopy es llamar a todos los constructores. La eliminación de ArrayTmp es una llamada a todos los destructores. Así que ArrayResize2 no es realmente ArrayResize.

Quizás debería llamarse ArrayReallocate, aunque no le veo ningún sentido a esa re-copia forzada. Causaría una ralentización innecesaria. Lo único es probablemente sólo si se requiere restablecer punteros para un array de objetos de clase (invalidar sus valores anteriores), si se contabiliza en alguna parte (pero es más bien una muleta)
 
Alexey Navoykov:
Entonces probablemente sería más correcto llamarlo ArrayReallocate, aunque no le veo ningún sentido a esa recopilación forzada. Frenado innecesario.

Liberar memoria es la única razón.