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 数组从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毫秒。
 
可能发生的情况是,你脱离了EA的框架模式,需要重新进入该模式。下面的专家顾问显示了如何做到这一点
// Создание 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 


如果你在框架模式下关闭专家顾问,并在标准模式下运行,它将显示在优化期间得到的相同数据。

这种方法允许你多次回到优化结果中 去。


SZY 在终端打开的框架模式的图表上,你不能运行任何专家顾问。因此,如果你想在标准模式下运行它,你应该在一个没有打开过框架的图表上运行它。

 
现在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可能更正确,尽管我不认为这种强制重写有任何意义。不必要的制动。

释放内存 是唯一的原因。