Features of the mql5 language, subtleties and tricks - 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:

Thank you. Using the ArraySwap function would not have occurred to me.

I understand that your function will work for both increasing and decreasing the size, i.e. as a full analogue of ArrayResize.

Isn't it better to simply call the standard ArrayResize function when an array is enlarged, rather than calling the three functionsArraySwap,ArrayResize,ArrayCopy?


p.s Tested your version and mine with two copies when reducing the MqlTick array from 1,000,000 to 500,0000. Your version does it in 22 milseconds. Mine does it in 37-38.
 
pivomoe:

Isn't it better to simply call the standard ArrayResize when an array is enlarged than to call three functionsArraySwap,ArrayResize,ArrayCopy

I thought about it, but didn't do it, because there are actually more subtleties. That's why I decided to stick with the laconic version.

One of the subtleties is this. If you take an array of structures with constructors/destructors, ArrayResize will call them in either direction in an amount equal to the difference in values.

But applying ArrayCopy is calling all constructors. Removing ArrayTmp is a call to all destructors. So ArrayResize2 is not really ArrayResize.

 
It turns out that you could just write ArrayResize( arr, new_size, -1) like this. But your version is still faster, about 22 vs. 37 milliseconds.
 
It may happen that you get out of the EA's frame mode and need to get back into it. The following Expert Advisor shows how to do this
// Создание 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 для Тестера.
}


After optimisation, you will see the following

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 


If you switch off the Expert Advisor in frame mode and run it in standard mode, it will show the same data that it got during optimization.

This approach allows you to go back to the Optimization results many times.


SZY On the chart which is opened in the Terminal for frame mode, you can't run any Expert Advisor. So if you want to run it in standard mode, you should run it on a chart which has not been opened for frames.

 
extern is now a hardcoded macro
#undef extern
#define extern // macro redefinition
Accordingly, it will not always be possible to make the MT5 mq4 code work without changes.
 

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

Accordingly, it will not always be possible to make the MT5 mq4 code work without changes.

There are no changes in the documentation. Can you explain this in more detail?

 
Alexey Viktorov:

There is no change in the documentation. Can you explain this in more detail?

Such a code

#property script_show_inputs

#define extern input // macro redefinition

extern int i = 0;

void OnStart() {}

will always generate a warning. I'm being a bit harsh about "impossible". It is possible to override, so just a warning will always hang in such situations.

 
fxsaber:

One of the nuances is this. If you take an array of structures with constructors/destructors, then ArrayResize in either direction calls them in a number equal to the difference in values.

But applying ArrayCopy is calling all constructors. Removing ArrayTmp is a call to all destructors. So ArrayResize2 is not really ArrayResize.

Perhaps it should be called ArrayReallocate, although I don't see any sense in such forced re-copying. It would cause unnecessary slowdown. The only thing is probably only if it's required to reset pointers for an array of class objects (invalidate their previous values), if it's accounted for somewhere (but it's rather a crutch)
 
Alexey Navoykov:
Then it would probably be more correct to call it ArrayReallocate, although I don't see any sense in such forced recopying. Unnecessary braking.

Freeing up memory is the only reason.

Reason: