Merkmale der Sprache mql5, Feinheiten und Techniken - Seite 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:

Ich danke Ihnen. Die Verwendung der Funktion ArraySwap wäre mir nicht in den Sinn gekommen.

Ich verstehe, dass Ihre Funktion sowohl für die Erhöhung als auch für die Verringerung der Größe, d.h. als ein volles Analogon von ArrayResize funktionieren wird.

Ist es nicht besser, einfach die Standardfunktion ArrayResize aufzurufen, wenn ein Array vergrößert wird, anstatt die drei FunktionenArraySwap,ArrayResize,ArrayCopy aufzurufen?


p.s. Ich habe Ihre Version und meine mit zwei Kopien getestet, als ich das Array MqlTick von 1.000.000 auf 500.0000 reduziert habe. Ihre Version schafft es in 22 Millisekunden. Meiner macht das in 37-38.
 
pivomoe:

Ist es nicht besser, einfach die Standardfunktion ArrayResize aufzurufen, wenn ein Array vergrößert wird, anstatt die drei FunktionenArraySwap,ArrayResize,ArrayCopy

Ich habe darüber nachgedacht, es aber nicht getan, weil es tatsächlich mehr Feinheiten gibt. Deshalb habe ich mich für die lakonische Version entschieden.

Eine der Feinheiten ist die folgende. Wenn Sie ein Array von Strukturen mit Konstruktoren/Destruktoren nehmen, wird ArrayResize sie in beiden Richtungen in einer Menge aufrufen, die der Differenz der Werte entspricht.

Aber die Anwendung von ArrayCopy ruft alle Konstruktoren auf. Das Entfernen von ArrayTmp ist ein Aufruf an alle Destruktoren. ArrayResize2 ist also nicht wirklich ArrayResize.

 
Es stellt sich heraus, dass man ArrayResize( arr, new_size, -1) einfach wie folgt schreiben könnte. Aber Ihre Version ist immer noch schneller, etwa 22 gegenüber 37 Millisekunden.
 
Es kann vorkommen, dass Sie aus dem Frame-Modus des EA herauskommen und wieder in diesen zurückkehren müssen. Der folgende Expert Advisor zeigt, wie man das macht
// Создание 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 для Тестера.
}


Nach der Optimierung werden Sie Folgendes sehen

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 


Wenn Sie den Expert Advisor im Frame-Modus ausschalten und ihn im Standardmodus ausführen, zeigt er die gleichen Daten an, die er während der Optimierung erhalten hat.

Auf diese Weise können Sie immer wieder auf die Optimierungsergebnisse zurückgreifen.


SZY Auf dem Chart, der im Terminal für den Frame-Modus geöffnet ist, können Sie keinen Expert Advisor ausführen. Wenn Sie es also im Standardmodus ausführen möchten, sollten Sie es auf einem Diagramm ausführen, das nicht für Frames geöffnet wurde.

 
extern ist jetzt ein fest kodiertes Makro
#undef extern
#define extern // macro redefinition
Daher wird es nicht immer möglich sein, den MT5 mq4-Code ohne Änderungen zum Laufen zu bringen.
 

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

Daher wird es nicht immer möglich sein, den MT5 mq4-Code ohne Änderungen zum Laufen zu bringen.

In der Dokumentation gibt es keine Änderungen. Können Sie dies näher erläutern?

 
Alexey Viktorov:

In der Dokumentation gibt es keine Änderungen. Können Sie dies näher erläutern?

Ein solcher Code

#property script_show_inputs

#define extern input // macro redefinition

extern int i = 0;

void OnStart() {}

wird immer eine Warnung ausgeben. Das Wort "unmöglich" ist etwas hart ausgedrückt. Es ist möglich, dies zu überschreiben, so dass in solchen Situationen immer nur eine Warnung angezeigt wird.

 
fxsaber:

Eine der Nuancen ist die folgende. Wenn Sie ein Array von Strukturen mit Konstruktoren/Destruktoren nehmen, dann ruft ArrayResize in beiden Richtungen eine Anzahl auf, die der Differenz der Werte entspricht.

Aber die Anwendung von ArrayCopy ruft alle Konstruktoren auf. Das Entfernen von ArrayTmp ist ein Aufruf an alle Destruktoren. ArrayResize2 ist also nicht wirklich ArrayResize.

Vielleicht sollte es ArrayReallocate genannt werden, obwohl ich keinen Sinn in einer solchen erzwungenen Neukopierung sehe. Dies würde zu einer unnötigen Verlangsamung führen. Die einzige Sache ist wahrscheinlich nur, wenn es erforderlich ist, Zeiger für ein Array von Klassenobjekten zurückzusetzen (ihre vorherigen Werte ungültig machen), wenn es irgendwo berücksichtigt wird (aber es ist eher eine Krücke)
 
Alexey Navoykov:
Dann wäre es wahrscheinlich korrekter, es ArrayReallocate zu nennen, obwohl ich keinen Sinn in einer solchen erzwungenen Umkopierung sehe. Unnötiges Bremsen.

DieFreigabe von Speicherplatz ist der einzige Grund.