Особенности языка mql5, тонкости и приёмы работы - страница 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:

Спасибо. Использовать функцию ArraySwap мне бы в голову не пришло.

Я так понимаю ваша функция будет, работать как при увеличении так при уменьшении размера т.е как полный аналог ArrayResize.

Не лучше ли при увеличении массива просто вызвать стандартную ArrayResize, чем вызывать три функции ArraySwap, ArrayResize, ArrayCopy


p.s Проверил вашу версию и мою с двумя копированиями при уменьшении массива MqlTick c 1 000 000 до 500 0000. Ваша версия справляется за 22 милесекуныд. Моя за 37-38.
 
pivomoe:

Не лучше ли при увеличении массива просто вызвать стандартную ArrayResize, чем вызывать три функции ArraySwap, ArrayResize, ArrayCopy

Думал об этом, но делать не стал, т.к. нюансов на самом деле больше. Поэтому решил остановиться на лаконичной версии.

Один из нюансов таков. Если брать массив из структур с конструкторами/деструкторами, то ArrayResize в любую из сторон вызывает их в количестве, равном разнице величин.

А вот применение ArrayCopy - это вызов всех конструкторов. Удаление ArrayTmp - вызов всех деструкторов. Так что ArrayResize2 - это не совсем ArrayResize.

 
Оказывается можно было просто вот так написать ArrayResize( arr, new_size, -1). Правда ваш вариант всё равно быстрее где то 22 против 37 миллисекунд .
 
Бывает, что вышел из фрейм-режима советника, а нужно вернуться в него. Следующий советник показывает, как это сделать
// Создание 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 для Тестера.
}


После Оптимизации увидите такое

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 


Если выключить советник во фрейм-режиме и запустить его в стандартном режиме, он покажет те же данные, что получал во время Оптимизации.

Такой подход позволяет многократно возращаться к результатам Оптимизации.


ЗЫ На чарте, что открывается в Терминале для фрейм-режиме советника, нельзя запустить не один советник. Поэтому если нужно запустить в стандартном режиме, нужно запускать на чартах, которые не были открыты для фреймов.

 
extern теперь является жестко заданным макросом
#undef extern
#define extern // macro redefinition
Соответственно, заставить работать в MT5 mq4-код без изменений не всегда будет возможно.
 

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

Соответственно, заставить работать в MT5 mq4-код без изменений не всегда будет возможно.

В документации нет изменений. Можете поподробней объяснить это?

 
Alexey Viktorov:

В документации нет изменений. Можете поподробней объяснить это?

Такой код

#property script_show_inputs

#define extern input // macro redefinition

extern int i = 0;

void OnStart() {}

всегда будет выдавать предупреждение. По поводу "невозможности" - погорячился. Переопределить возможно, так что просто предупреждения будут висеть всегда в таких ситуациях.

 
fxsaber:

Один из нюансов таков. Если брать массив из структур с конструкторами/деструкторами, то ArrayResize в любую из сторон вызывает их в количестве, равном разнице величин.

А вот применение ArrayCopy - это вызов всех конструкторов. Удаление ArrayTmp - вызов всех деструкторов. Так что ArrayResize2 - это не совсем ArrayResize.

Тогда наверное правильнее называть это ArrayReallocate.  Хотя какого-то смысла таком принудительном перекопировании не вижу. Лишние тормоза. Единственное наверно только если требуется для массива объектов класса сбросить указатели (сделать невалидными их прежние значения), если это где-то учитывается (но это скорее костыль)
 
Alexey Navoykov:
Тогда наверное правильнее называть это ArrayReallocate.  Хотя какого-то смысла таком принудительном перекопировании не вижу. Лишние тормоза.

Освобождение памяти - единственная причина.