Caractéristiques du langage mql5, subtilités et techniques - page 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:

Merci. L'utilisation de la fonction ArraySwap ne m'aurait pas effleuré.

Je comprends que votre fonction fonctionnera à la fois en augmentant et en diminuant la taille, c'est-à-dire comme un analogue complet de ArrayResize.

N'est-il pas préférable d'appeler simplement la fonction standard ArrayResize lorsqu'un tableau est agrandi, plutôt que d'appeler les trois fonctionsArraySwap,ArrayResize,ArrayCopy?


p.s J'ai testé votre version et la mienne avec deux copies en réduisant le tableau MqlTick de 1.000.000 à 500.0000. Votre version le fait en 22 millisecondes. Le mien le fait en 37-38.
 
pivomoe:

N'est-il pas préférable d'appeler simplement la fonction standard ArrayResize lorsqu'un tableau est étendu, plutôt que d'appeler les trois fonctionsArraySwap,ArrayResize,ArrayCopy

J'y ai pensé, mais je ne l'ai pas fait, car il y a en fait plus de subtilités. C'est pourquoi j'ai décidé de m'en tenir à la version laconique.

Une des subtilités est la suivante. Si vous prenez un tableau de structures avec des constructeurs/destructeurs, ArrayResize les appellera dans les deux sens dans une quantité égale à la différence de valeurs.

Mais l'application de ArrayCopy appelle tous les constructeurs. La suppression de ArrayTmp est un appel à tous les destructeurs. Donc ArrayResize2 n'est pas vraiment ArrayResize.

 
Il s'avère que vous pourriez simplement écrire ArrayResize( arr, new_size, -1) comme ceci. Mais votre version est toujours plus rapide, environ 22 contre 37 millisecondes.
 
Il peut arriver que vous sortiez du mode cadre de l'EA et que vous deviez y revenir. Le conseiller expert suivant montre comment procéder
// Создание 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 для Тестера.
}


Après l'optimisation, vous verrez ce qui suit

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 vous désactivez le conseiller expert en mode cadre et que vous l'exécutez en mode standard, il affichera les mêmes données que celles obtenues pendant l'optimisation.

Cette approche vous permet de revenir plusieurs fois sur les résultats de l'optimisation.


SZY Sur le graphique qui est ouvert dans le Terminal pour le mode frame, vous ne pouvez pas exécuter d'EA. Donc, si vous voulez l'exécuter en mode standard, vous devez l'exécuter sur un graphique qui n'a pas été ouvert pour les cadres.

 
extern est maintenant une macro codée en dur
#undef extern
#define extern // macro redefinition
Par conséquent, il ne sera pas toujours possible de faire fonctionner le code MT5 mq4 sans modifications.
 

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

Par conséquent, il ne sera pas toujours possible de faire fonctionner le code MT5 mq4 sans modifications.

Il n'y a pas de changement dans la documentation. Pouvez-vous expliquer cela plus en détail ?

 
Alexey Viktorov:

Il n'y a pas de changement dans la documentation. Pouvez-vous expliquer cela plus en détail ?

Un tel code

#property script_show_inputs

#define extern input // macro redefinition

extern int i = 0;

void OnStart() {}

générera toujours un avertissement. Je suis un peu dur avec le mot "impossible". Il est possible de passer outre, de sorte qu'un simple avertissement sera toujours affiché dans de telles situations.

 
fxsaber:

Une des nuances est la suivante. Si vous prenez un tableau de structures avec des constructeurs/destructeurs, alors ArrayResize dans un sens ou dans l'autre les appelle en un nombre égal à la différence de valeurs.

Mais l'application de ArrayCopy appelle tous les constructeurs. La suppression de ArrayTmp est un appel à tous les destructeurs. Donc ArrayResize2 n'est pas vraiment ArrayResize.

Peut-être devrait-il s'appeler ArrayReallocate, bien que je ne voie pas l'intérêt d'une telle recopie forcée. Cela provoquerait un ralentissement inutile. La seule chose à faire est probablement de réinitialiser les pointeurs d'un tableau d'objets de classe (invalider leurs valeurs précédentes), si c'est prévu quelque part (mais c'est plutôt une béquille).
 
Alexey Navoykov:
Dans ce cas, il serait probablement plus correct de l'appeler ArrayReallocate, bien que je ne voie pas l'intérêt d'une telle recopie forcée. Freinage inutile.

Libérer de la mémoire est la seule raison.

Raison: