Características da linguagem mql5, subtilezas e 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:

Obrigado. A utilização da função ArraySwap não me teria ocorrido.

Compreendo que a sua função funcionará tanto ao aumentar como ao diminuir o tamanho, ou seja, como um análogo completo do ArrayResize.

Não será melhor simplesmente chamar a função padrão ArrayResize quando um array é aumentado, em vez de chamar as três funçõesArraySwap,ArrayResize,ArrayCopy?


p.s Testou a sua versão e a minha com duas cópias ao reduzir a matriz MqlTick de 1.000.000 para 500.0000. A sua versão fá-lo em 22 milésimos de segundo. O meu fá-lo em 37-38.
 
pivomoe:

Não é melhor simplesmente chamar o ArrayResize padrão quando um array é aumentado do que chamar três funçõesArraySwap,ArrayResize,ArrayCopy

Pensei sobre isso, mas não o fiz, porque na realidade há mais subtilezas. Foi por isso que decidi manter a versão lacónica.

Uma das subtilezas é esta. Se tomar um conjunto de estruturas com construtores/destructores, o ArrayResize chamá-los-á em qualquer direcção numa quantidade igual à diferença de valores.

Mas a aplicação do ArrayCopy está a chamar todos os construtores. A remoção do ArrayTmp é uma chamada a todos os destruidores. Portanto, o ArrayResize2 não é realmente o ArrayResize.

 
Acontece que poderia simplesmente escrever ArrayResize( arr, new_size, -1) desta forma. Mas a sua versão é ainda mais rápida, cerca de 22 vs. 37 milissegundos.
 
Pode acontecer que saia do modo frame da EA e precise de voltar a entrar nele. O seguinte consultor especializado mostra como fazer isto
// Создание 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 для Тестера.
}


Após a optimização, verá o seguinte

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 


Se desligar o Expert Advisor em modo frame e o executar em modo standard, este mostrará os mesmos dados que obteve durante a optimização.

Esta abordagem permite-lhe voltar muitas vezes aos resultados da Optimização.


SZY Na tabela que se abre no Terminal para o modo frame, não se pode executar nenhuma EA. Por isso, se quiser executá-lo em modo padrão, deve executá-lo num gráfico que não tenha sido aberto para molduras.

 
exterior é agora uma macro codificada
#undef extern
#define extern // macro redefinition
Assim, nem sempre será possível fazer o código MT5 mq4 funcionar sem alterações.
 

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

Assim, nem sempre será possível fazer o código MT5 mq4 funcionar sem alterações.

Não há alterações na documentação. Pode explicar isto com mais detalhe?

 
Alexey Viktorov:

Não há qualquer alteração na documentação. Pode explicar isto com mais detalhe?

Um tal código

#property script_show_inputs

#define extern input // macro redefinition

extern int i = 0;

void OnStart() {}

irá sempre gerar um aviso. Estou a ser um pouco duro em relação ao "impossível". É possível anular, pelo que apenas um aviso será sempre pendurado em tais situações.

 
fxsaber:

Uma das nuances é esta. Se tomar um conjunto de estruturas com construtores/destructores, então o ArrayResize em qualquer direcção chama-os num número igual à diferença de valores.

Mas a aplicação do ArrayCopy está a chamar todos os construtores. A remoção do ArrayTmp é uma chamada a todos os destruidores. Portanto, o ArrayResize2 não é realmente o ArrayResize.

Talvez se devesse chamar ArrayReallocate, embora eu não veja qualquer sentido em tal recopiar forçado. Provocaria um abrandamento desnecessário. A única coisa é provavelmente apenas se for necessário reiniciar os apontadores para um conjunto de objectos de classe (invalidar os seus valores anteriores), se for contabilizado em algum lugar (mas é antes uma muleta)
 
Alexey Navoykov:
Então seria provavelmente mais correcto chamar-lhe ArrayReallocate, embora eu não veja qualquer sentido em tal recoperação forçada. Travagem desnecessária.

Libertar a memória é a única razão.