Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 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:

Grazie. Usare la funzione ArraySwap non mi sarebbe venuto in mente.

Ho capito che la tua funzione funzionerà sia quando si aumenta che quando si diminuisce la dimensione, cioè come un analogo completo di ArrayResize.

Non è meglio chiamare semplicemente la funzione standard ArrayResize quando un array viene ingrandito, piuttosto che chiamare le tre funzioniArraySwap,ArrayResize,ArrayCopy?


p.s Testato la tua versione e la mia con due copie quando si riduce l'array MqlTick da 1.000.000 a 500.0000. La tua versione lo fa in 22 milsecondi. Il mio lo fa in 37-38.
 
pivomoe:

Non è meglio chiamare semplicemente lo standard ArrayResize quando un array viene espanso, piuttosto che chiamare le tre funzioniArraySwap,ArrayResize,ArrayCopy

Ci ho pensato, ma non l'ho fatto, perché in realtà ci sono più sottigliezze. Ecco perché ho deciso di attenermi alla versione laconica.

Una delle sottigliezze è questa. Se prendete un array di strutture con costruttori/distruttori, ArrayResize li richiamerà in entrambe le direzioni in una quantità pari alla differenza di valori.

Ma applicare ArrayCopy significa chiamare tutti i costruttori. La rimozione di ArrayTmp è una chiamata a tutti i distruttori. Quindi ArrayResize2 non è veramente ArrayResize.

 
Si scopre che si potrebbe semplicemente scrivere ArrayResize( arr, new_size, -1) in questo modo. Ma la tua versione è ancora più veloce, circa 22 contro 37 millisecondi.
 
Può succedere che si esca dalla modalità di inquadramento dell'EA e che sia necessario rientrarci. Il seguente Expert Advisor mostra come fare questo
// Создание 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 для Тестера.
}


Dopo l'ottimizzazione, vedrete quanto segue

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 spegni l'Expert Advisor in modalità frame e lo esegui in modalità standard, mostrerà gli stessi dati che ha ottenuto durante l'ottimizzazione.

Questo approccio permette di tornare più volte ai risultati dell'ottimizzazione.


SZY Sul grafico aperto nel Terminale per la modalità frame, non è possibile eseguire alcun EA. Quindi, se volete eseguirlo in modalità standard, dovreste eseguirlo su un grafico che non è stato aperto per i frame.

 
extern è ora una macro hardcoded
#undef extern
#define extern // macro redefinition
Di conseguenza, non sarà sempre possibile far funzionare il codice MT5 mq4 senza modifiche.
 

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

Di conseguenza, non sarà sempre possibile far funzionare il codice MT5 mq4 senza modifiche.

Non ci sono cambiamenti nella documentazione. Puoi spiegare questo in modo più dettagliato?

 
Alexey Viktorov:

Non c'è nessun cambiamento nella documentazione. Puoi spiegare questo in modo più dettagliato?

Tale codice

#property script_show_inputs

#define extern input // macro redefinition

extern int i = 0;

void OnStart() {}

genererà sempre un avvertimento. Sono un po' duro su "impossibile". È possibile sovrascrivere, quindi solo un avvertimento sarà sempre appeso in tali situazioni.

 
fxsaber:

Una delle sfumature è questa. Se prendete un array di strutture con costruttori/distruttori, allora ArrayResize in entrambe le direzioni li chiama in un numero pari alla differenza di valori.

Ma applicare ArrayCopy significa chiamare tutti i costruttori. La rimozione di ArrayTmp è una chiamata a tutti i distruttori. Quindi ArrayResize2 non è veramente ArrayResize.

Forse dovrebbe essere chiamato ArrayReallocate, anche se non vedo alcun senso in una tale ricopiatura forzata. Causerebbe un rallentamento non necessario. L'unica cosa è probabilmente solo se è richiesto di resettare i puntatori per un array di oggetti di classe (invalidare i loro valori precedenti), se è contabilizzato da qualche parte (ma è piuttosto una stampella)
 
Alexey Navoykov:
Allora sarebbe probabilmente più corretto chiamarlo ArrayReallocate, anche se non vedo alcun senso in questa ricopiatura forzata. Frenata inutile.

Liberare la memoria è l'unica ragione.