Скачать MetaTrader 5

Порядок создания и уничтожения объектов в MQL5

1 марта 2010, 13:59
MetaQuotes Software Corp.
9
3 237

О чем эта статья

Язык MQL5 позволяет писать в стиле объектно-ориентированного программирования (ООП), и это не только открывает новые возможности для создания собственных библиотек, но и позволяет использовать уже готовые, разработанные и протестированные классы других разработчиков. В стандартной библиотеке из поставки терминала MetaTrader 5 уже реализованы сотни классов, которые содержат тысячи методов.

Чтобы успешно использовать все преимущества ООП, необходимо уяснить некоторые тонкости, связанные с созданием и уничтожением объектов в программах на языке MQL5. В Документации кратко описано создание и уничтожение объектов в MQL5, эта статья проиллюстрирует указанный раздел примерами.

Инициализация и деинициализация глобальных переменных

Инициализация глобальных переменных производится сразу после загрузки mql5-программы и до вызова любой функции. При инициализации производится присвоение начальных значений переменным простых типов и вызывается конструктор для объектов, если он в них объявлен.

Рассмотрим простой пример, в котором объявим два класса CObjectA и CObjectB, каждый класс имеет конструктор и деструктор, состоящий только из функции Print(). Переменные, имеющие тип этих классов, объявим на глобальном уровне и запустим скрипт.

//+------------------------------------------------------------------+
//|                                         GlobalVar_TestScript.mq5 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
class CObjectA
  {
public:
                     CObjectA(){Print(__FUNCTION__," Constructor");}
                    ~CObjectA(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CObjectB
  {
public:
                     CObjectB(){Print(__FUNCTION__," Constructor");}
                    ~CObjectB(){Print(__FUNCTION__," Destructor");}
  };
//--- объявим объекты на глобальном уровне
CObjectA first;
CObjectB second;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   Print(__FUNCTION__);
  }

Результат выполнения скрипта выводится в журнал "Эксперты":

GlobalVar_TestScript (EURUSD,H1)    13:05:07    CObjectA::ObjectA  Constructor
GlobalVar_TestScript (EURUSD,H1)    13:05:07    CObjectB::ObjectB  Constructor
GlobalVar_TestScript (EURUSD,H1)    13:05:07    OnStart
GlobalVar_TestScript (EURUSD,H1)    13:05:07    CObjectB::~ObjectB  Destructor
GlobalVar_TestScript (EURUSD,H1)    13:05:07    CObjectA::~ObjectA  Destructor

Из журнала видно,что порядок инициализации соответствует порядку объявления переменных в коде скрипта GlobalVar_TestScript.mq5, а деинициализация производится в обратном порядке перед выгрузкой mql5-программы.

Инициализация и деинициализация локальных переменных

Локальные переменные деинициализируются в конце блока программы, в котором они объявлены и в порядке, обратном их объявлению. Блок программы – это составной оператор, который может являться частью оператора выбора switch, цикла(for, while, do-while), телом функции или частью оператора if-else.

Инициализация локальных переменных происходит лишь в том случае, если выполнение программы доходит до объявления переменной. Если даже переменная объявлена в коде, но в ходе выполнения программы блок, в котором производится  объявление, не был выполнен, то такая переменная не создается, а следовательно, и не инициализируется.

Для иллюстрации к уже знакомым классам CObjectA и CObjectB добавим новый класс CObjectС. Объявления классов по-прежнему идут на глобальном уровне, но объявления переменных этих классов теперь разместим локально в функции OnStart().

Переменную класса CObjectA объявим безусловно сразу в первой исполняемой строке функции,  но объекты классов CObjectB и CObjectС объявим в разных блоках, которые выполняются в зависимости от значения input-переменной execute. В редакторе MetaEditor входные переменные mql5-программ подсвечиваются коричневым цветом.

//+------------------------------------------------------------------+
//|                                          LocalVar_TestScript.mq5 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property script_show_inputs
//--- input parameters
input bool     execute=false;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CObjectA
  {
public:
                     CObjectA(){Print(__FUNCTION__," Constructor");}
                    ~CObjectA(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CObjectB
  {
public:
                     CObjectB(){Print(__FUNCTION__," Constructor");}
                    ~CObjectB(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CObjectC
  {
public:
                     CObjectC(){Print(__FUNCTION__," Constructor");}
                    ~CObjectC(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   CObjectA objA;
//--- этот блок не выполнится, если execute==false
   if(execute)
     {
      CObjectB objB;
     }
//--- этот блок выполнится, если execute==false
   if(!execute)
     {
      CObjectC objC;
     }
  }
//+------------------------------------------------------------------+

Результат:

LocalVar_TestScript (GBPUSD,H1)    18:29:00    CObjectA::CObjectA  Constructor
LocalVar_TestScript (GBPUSD,H1)    18:29:00    CObjectC::CObjectC  Constructor
LocalVar_TestScript (GBPUSD,H1)    18:29:00    CObjectC::~CObjectC  Destructor
LocalVar_TestScript (GBPUSD,H1)    18:29:00    CObjectA::~CObjectA  Destructor

C каким бы значением входного параметра execute мы не запускали этот скрипт, первым всегда автоматически инициализируется объект класса CObjectA, за ним автоматически инициализируется тот объект( objB или objC), чей блок объявления был исполнен в зависимости от истинности execute. По умолчанию, этот параметр имеет значение false, в этом случае после инициализации переменной objA происходит инициализация переменной objC. Факт инициализации и деинициализации хорошо виден по выполнению конструктора и деструктора.

Но каков бы ни был порядок инициализации (независимо от параметра execute), деинициализация переменных сложных типов всегда производится в порядке, обратном порядку их инициализации. Это общее свойство как для локальных, так и для глобальных автоматически создаваемых объектов классов. В этом отношении разницы между ними нет.

Инициализация и деинициализация динамически создаваемых объектов

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

Указатели могут быть объявлены на локальном и/или глобальном уровне, и при этом могут быть проинициализированы пустым значением NULL порожденного типа. Создание объекта производится только в  тот момент, когда к указателю объекта применяется оператор new, и не связано с моментом объявления указателя объекта. 

Уничтожение динамического объекта производится посредством оператора delete, поэтому необходимо самостоятельно позаботиться об этом. Рассмотрим пример, в котором на глобальном уровне объявим две переменные типа CObjectA и CObjectB, а также одну переменную с указателем объекта типа CObjectC - назовем ее pObjectC.

//+------------------------------------------------------------------+
//|                                       GlobalVar_TestScript_2.mq5 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
class CObjectA
  {
public:
                     CObjectA(){Print(__FUNCTION__," Constructor");}
                    ~CObjectA(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CObjectB
  {
public:
                     CObjectB(){Print(__FUNCTION__," Constructor");}
                    ~CObjectB(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CObjectC
  {
public:
                     CObjectC(){Print(__FUNCTION__," Constructor");}
                    ~CObjectC(){Print(__FUNCTION__," Destructor");}
  };
CObjectC *pObjectC;
CObjectA first;
CObjectB second;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   pObjectC=new CObjectC;
   Print(__FUNCTION__);
   delete(pObjectC);
  }
//+------------------------------------------------------------------+

Несмотря на то, что указатель pObjectC  динамически созданного объекта объявлен ранее статических переменных first и second, инициализация этого объекта производится только в тот момент, когда объект создается оператором new. В данном примере оператор new расположен в функции OnStart().

GlobalVar_TestScript_2 (EURUSD,H1)    15:03:21    CObjectA::CObjectA  Constructor
GlobalVar_TestScript_2 (EURUSD,H1)    15:03:21    CObjectB::CObjectB  Constructor
GlobalVar_TestScript_2 (EURUSD,H1)    15:03:21    CObjectC::CObjectC  Constructor
GlobalVar_TestScript_2 (EURUSD,H1)    15:03:21    OnStart
GlobalVar_TestScript_2 (EURUSD,H1)    15:03:21    CObjectC::~CObjectC  Destructor
GlobalVar_TestScript_2 (EURUSD,H1)    15:03:21    CObjectB::~CObjectB  Destructor
GlobalVar_TestScript_2 (EURUSD,H1)    15:03:21    CObjectA::~CObjectA  Destructor

В тот момент, когда выполнение программы внутри функции OnStart() доходит до оператора

   pObjectC=new CObjectC;

происходит инициализация объекта и вызов конструктора для него. Затем происходит выполнение строчки

   Print(__FUNCTION__);

которая выводит в журнал строчку

GlobalVar_TestScript_2 (EURUSD,H1)    15:03:21    OnStart

и затем динамически созданный объект уничтожается вызовом для него оператора delete:

   delete(pObjectC);

Таким образом, объекты создаются динамически в момент создания оператором new и уничтожаются оператором delete.

Обязательное требование: все объекты, созданные выражением указатель_объекта=new Имя_Класса, обязательно должны быть впоследствии уничтожены оператором delete(указатель_объекта). Если по каким то причинам динамически созданный объект при выходе управления из блока, где он был инициализирован, не был уничтожен оператором delete, то об этом будет выведено сообщение в журнал "Эксперты".


Удаление динамически создаваемых объектов

Как уже говорилось, каждый динамически создаваемый объект инициализируется оператором new и должен обязательно явно уничтожаться оператором delete. Но при этом необходимо помнить, что оператор new создает объект и возвращает указатель этого объекта. Сам созданный объект не находится в переменной, содержащей указатель объекта. Можно объявить несколько указателей, и всем им присвоить указатель одного и того же объекта.

//+------------------------------------------------------------------+
//|                                        LocalVar_TestScript_1.mq5 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|  простой класс                                                   |
//+------------------------------------------------------------------+
class CItem
  {
public:
                     CItem(){Print(__FUNCTION__," Constructor");}
                    ~CItem(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- объявим первый массив указателей на объект
   CItem* array1[5];
//--- объявим второй массив указателей на объект
   CItem* array2[5];
//--- теперь заполним массивы в цикле
   for(int i=0;i<5;i++)
     {
      //--- указатель для первого массива создадим оператором new
      array1[i]=new CItem;
      //--- указатель для второго массива создадим скопируем из первого массива
      array2[i]=array1[i];
     }
   // мы "забыли" удалить объекты перед выходом из функции,смотрим закладку "Эксперты"
  }
//+------------------------------------------------------------------+

Будет выведено сообщение о том, что остались неудаленные объекты. Но этих объектов будет не 10, как можно ошибочно ожидать, а 5. Ведь создали мы оператором new только 5 объектов.

(GBPUSD,H1)    12:14:04    CItem::CItem  Constructor
(GBPUSD,H1)    12:14:04    CItem::CItem  Constructor
(GBPUSD,H1)    12:14:04    CItem::CItem  Constructor
(GBPUSD,H1)    12:14:04    CItem::CItem  Constructor
(GBPUSD,H1)    12:14:04    CItem::CItem  Constructor
(GBPUSD,H1)    12:14:04    5 undeleted objects left

Если даже для динамически созданного объекта деструктор не вызывается (объект не уничтожается оператором delete), то память все равно будет освобождена. Но при этом в журнал "Эксперты" выводится сообщение, что объект не удален. Это позволяет выявить факт неправильного управления объектами в программе и устранить ошибку.

Изменим немного пример – попытаемся уничтожить указатели в каждом из двух массивов указателей array1 и array2.

//+------------------------------------------------------------------+
//|                                        LocalVar_TestScript_2.mq5 |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|  простой класс                                                   |
//+------------------------------------------------------------------+
class CItem
  {
public:
                     CItem(){Print(__FUNCTION__," Constructor");}
                    ~CItem(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- объявим первый массив указателей на объект
   CItem* array1[5];
//--- объявим второй массив указателей на объект
   CItem* array2[5];
//--- теперь заполним массивы в цикле
   for(int i=0;i<5;i++)
     {
      //--- указатель для первого массива создадим оператором new
      array1[i]=new CItem;
      //--- указатель для второго массива скопируем из первого массива
      array2[i]=array1[i];
     }
//--- уничтожим объекты по указателям второго массива
   for(int i=0;i<5;i++) delete(array2[i]);
//--- теперь попытаемся уничтожить объекты по указателям первого массива
   for(int i=0;i<5;i++) delete(array2[i]);
// получим сообщения в закладке "Эксперты" о попытках удаления для некорректного указателя 
  }
//+------------------------------------------------------------------+

Результат выполнения скрипта в закладке "Эксперты" теперь выглядит по-другому.

(GBPUSD,H1)    15:02:48    CItem::CItem  Constructor
(GBPUSD,H1)    15:02:48    CItem::CItem  Constructor
(GBPUSD,H1)    15:02:48    CItem::CItem  Constructor
(GBPUSD,H1)    15:02:48    CItem::CItem  Constructor
(GBPUSD,H1)    15:02:48    CItem::CItem  Constructor
(GBPUSD,H1)    15:02:48    CItem::~CItem  Destructor
(GBPUSD,H1)    15:02:48    CItem::~CItem  Destructor
(GBPUSD,H1)    15:02:48    CItem::~CItem  Destructor
(GBPUSD,H1)    15:02:48    CItem::~CItem  Destructor
(GBPUSD,H1)    15:02:48    CItem::~CItem  Destructor
(GBPUSD,H1)    15:02:48    delete invalid pointer
(GBPUSD,H1)    15:02:48    delete invalid pointer
(GBPUSD,H1)    15:02:48    delete invalid pointer
(GBPUSD,H1)    15:02:48    delete invalid pointer
(GBPUSD,H1)    15:02:48    delete invalid pointer

Созданные объекты CItem были успешно удалены в первом цикле for(), все попытки удаления уже несуществующих объектов во втором цикле вызвали появление сообщений о некорректных указателях. Удалять динамически созданный объект всегда нужно однократно, и перед использованием любого указателя объекта желательно его проверять функцией CheckPointer().

Проверка указателя объекта функцией CheckPointer()

Функция CheckPointer() служит для проверки указателей и позволяет определить тип указателя. Возможны две ошибки при работе с динамически созданными объектами:

  • неудаление в конце блока выполнения;
  • попытка удаления уже несуществующего объекта.

Рассмотрим еще один пример, который демонстрирует взаимоотношение объектов. Спроектируем два класса, один класс - CItemArray - содержит в себе массив указателей другого класса: CItem.

//+------------------------------------------------------------------+
//|                                        LocalVar_TestScript_3.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|  простой класс                                                   |
//+------------------------------------------------------------------+
class CItem
  {
public:
                     CItem(){Print(__FUNCTION__," Constructor");}
                    ~CItem(){Print(__FUNCTION__," Destructor");}
  };
//+------------------------------------------------------------------+
//| класс для хранения массива указателей CItem                      |
//+------------------------------------------------------------------+
class CItemArray
  {
private:
   CItem            *m_array[];
public:
                     CItemArray(){Print(__FUNCTION__," Constructor");}
                    ~CItemArray(){Print(__FUNCTION__," Destructor");Destroy();}
   void               SetArray(CItem &array[]);
protected:
   void               Destroy();
  };
//+------------------------------------------------------------------+
//|  заполнение массива указателей                                   |
//+------------------------------------------------------------------+
CItemArray::SetArray(CItem &array[])
  {
   int size=ArraySize(array);
   ArrayResize(m_array,size);
   for(int i=0;i<size;i++)m_array[i]=GetPointer(array[i]);
  }
//+------------------------------------------------------------------+
//|  освобождение                                                    |
//+------------------------------------------------------------------+
CItemArray::Destroy(void)
  {
   for(int i=0;i<ArraySize(m_array);i++)
     {
      if(CheckPointer(m_array[i])!=POINTER_INVALID)
        {
         if(CheckPointer(m_array[i])==POINTER_DYNAMIC) delete(m_array[i]);
        }
      else Print("Invalid pointer to delete");
     }
  }

Сами по себе классы никакой ошибки не содержат, но вот их применение может также принести сюрпризы. Первый вариант скрипта:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   CItemArray items_array;
   CItem array[5];
   items_array.SetArray(array);
  }

При запуске этого варианта получаем следующие сообщения:

(GBPUSD,H1)    16:06:17    CItemArray::CItemArray  Constructor
(GBPUSD,H1)    16:06:17    CItem::CItem  Constructor
(GBPUSD,H1)    16:06:17    CItem::CItem  Constructor
(GBPUSD,H1)    16:06:17    CItem::CItem  Constructor
(GBPUSD,H1)    16:06:17    CItem::CItem  Constructor
(GBPUSD,H1)    16:06:17    CItem::CItem  Constructor
(GBPUSD,H1)    16:06:17    CItem::~CItem  Destructor
(GBPUSD,H1)    16:06:17    CItem::~CItem  Destructor
(GBPUSD,H1)    16:06:17    CItem::~CItem  Destructor
(GBPUSD,H1)    16:06:17    CItem::~CItem  Destructor
(GBPUSD,H1)    16:06:17    CItem::~CItem  Destructor
(GBPUSD,H1)    16:06:17    CItemArray::~CItemArray  Destructor
(GBPUSD,H1)    16:06:17    Invalid pointer to delete
(GBPUSD,H1)    16:06:17    Invalid pointer to delete
(GBPUSD,H1)    16:06:17    Invalid pointer to delete
(GBPUSD,H1)    16:06:17    Invalid pointer to delete

Так как в функции первым идет объявление переменной класса CItemArray, то первой производится инициализация именно этой переменной и вызывается конструктор  класса. Затем объявляется массив array[5], содержащий указатели объектов класса CItem. Поэтому мы видим 5 сообщений об инициализации каждого такого объекта.

Последней строчкой этого простого скрипта производится копирование указателей из массива array[5] во внутренний массив указателей объекта items_array.

   items_array.SetArray(array);

На этом выполнение скрипта заканчивается и производится автоматическое уничтожение автоматически созданных объектов. Первым уничтожается тот объект, который был инициализирован последним - это массив указателей array[5]. Это подтверждено в Журнале пятью записями о вызове деструктора класса CItem. Затем идет сообщение о вызове деструктора для объекта items_array, так как он был проинициализирован непосредственно перед переменной array[5].

Но деструктор класса CArrayItem вызывает защищенную функцию Destroy(), в которой производится попытка уничтожения объектов CItem через указатели в m_array[] через оператор delete. Предварительно производится проверка указателя, и если указатель является некорректным, то попытка удаления не производится, а выводится сообщение "Invalid pointer to delete".

Всего таких сообщений в Журнале 5, то есть все указатели в массиве m_array[] оказались некорректными. Это произошло потому, что эти объекты данных указателей уже были деинициализрованы при деинициализации массива array[].

Изменим скрипт совсем немного – поменяем местами объявление переменных items_array и items_array[] местами (См. 'LocalVar_TestScript_4.mq5').

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   CItem array[5];
   CItemArray items_array;
   items_array.SetArray(array);
  }

Исправленный вариант никаких сообщений об ошибках не выдает. Первой теперь был деинициализирована переменная items_array, так как была объявлена последней. При ее деинициализации был вызван деструктор класса ~CItemArray(), в котором в свою очередь вызывается функция Destroy().

При таком порядке объявления уничтожение items_array происходит до уничтожения массива объектов array[5]. В функции Destroy(), которая вызывается из деструктора items_array, работа ведётся с указателями на ещё существующие объекты, поэтому никаких ошибок не возникает.

Третий пример правильного удаления динамически созданных объектов можно посмотреть в разделе функции GetPointer(). В приведенном там примере явным образом вызывается функция Destroy() для обеспечения нужного порядка удаления объектов.

Заключение

Как видите, ничего сложного в понимании механизмов создания и уничтожения объектов нет. Достаточно выполнить все приведенные в статье примеры, и в дальнейшем вы сами сможете придумывать свои варианты взаимодействия между автоматически и динамически созданными объектами.

Обязательно проверяйте свои классы на корректность удаления объектов и правильно проектируйте деструкторы, чтобы не возникало ошибок при попытке доступа к некорректным указателям. Помните, что в случае использования динамически создаваемых объектов оператором new, необходимо уметь правильно уничтожать эти объекты оператором delete.

В этой статье мы изучили только порядок создания и уничтожения объектов в MQL5. Как организовать безопасную работу с указателями объектов- тема отдельной статьи.

Владимир
Владимир | 31 янв 2011 в 16:28
Оператор new нужен только чтоб класс был динамическим? Но если динамический массив - это "массив с неуказанным значением в первой паре квадратных скобок", то динамичекий класс это что?
Ilyas
Ilyas | 31 янв 2011 в 21:24
Burgunsky:

А почему вот эта строчка приводит к запуску конструктора:

Проверил, никакого вызова конструктора не происходит, приложите весь код пожалуйста
Yedelkin
Yedelkin | 31 янв 2011 в 21:29
Burgunsky:

А почему вот эта строчка приводит к запуску конструктора:  CItem* array1[5];,

а вот эта нет: CObjectC *pObjectC;    ?

Я понял так, что строчка

CItem* array1[5];

сама по себе не приводит к запуску конструктора. Вот более полный код из статьи:

void OnStart()
  {
//--- объявим первый массив указателей на объект
   CItem* array1[5];
//--- объявим второй массив указателей на объект
   CItem* array2[5];
//--- теперь заполним массивы в цикле
   for(int i=0;i<5;i++)
     {
      //--- указатель для первого массива создадим оператором new
      array1[i]=new CItem;
      //--- указатель для второго массива скопируем из первого массива
      array2[i]=array1[i];
     }
Конструктор вызывается не при объявлении первого массива указателей, а при заполнении этого массива в цикле с помощью оператора new.
Yedelkin
Yedelkin | 31 янв 2011 в 21:36

 
Burgunsky:
Оператор new нужен только чтоб класс был динамическим? Но если динамический массив - это "массив с неуказанным значением в первой паре квадратных скобок", то динамичекий класс это что?
Я понял так, что слово "динамический" в программировании является многозначным. Применительно к классам идёт противопоставление: "автоматически созданный объект" vs "динамически созданный объект". Различие между ними примерно такое же, как между переменными, объявленными на глобальном уровне, и переменными, объявленными на локальном уровне. Иными словами, "динамически созданный объект" - это объект, созданный "на время", время жизни - от момента создания оператором new до момента удаления оператором delete. 
sigma7i
sigma7i | 7 июн 2013 в 14:56

Но всеравно остались вопросы:

В чем смысл создания динамического объекта через оператор new?

При автоматическом создании объекта, объект класса создается в стеке, по времени исполнения он быстрее нежели динамический.

При динамическом создании объекта, объект класса создается в памяти(в куче) при этом задействуя  менеджер памяти ОС процесс происходит медленнее.

Вот вопрос: если автоматическое создание быстрее то почему тогда создаются динамические объекты? Чтобы стек не переполнился?

Переход на новые рельсы: пользовательские индикаторы в MQL5 Переход на новые рельсы: пользовательские индикаторы в MQL5

Я не буду перечислять все новые возможности и особенности нового терминала и языка. Их действительно много, и некоторые новинки вполне достойны освещения в отдельной статье. Вы не увидите здесь кода, написанного по принципам объектно-ориентированного программирования — это слишком серьезная тема для того, чтобы просто быть упомянутой в контексте как дополнительная вкусность для кодописателей. В этой статье остановимся подробней на индикаторах, их строении, отображении, видах, а также особенностях их написания по сравнению с MQL4.

Вот мы и получили долгожданные MetaTrader 5 и MQL5 Вот мы и получили долгожданные MetaTrader 5 и MQL5

Это очень краткий обзор MetaTrader 5. Я не могу описать все новшества системы за столь короткий период времени - тестирование стартовало 09-09-2009. Это символическая дата, и я уверен, что это будет счастливым числом. Всего несколько дней у меня на руках бета-версия терминала MetaTrader 5 и MQL5. Я не успел опробовать все, что в нем есть нового, но то, что есть, уже впечатляет.

Работа с корзинами валютных пар на рынке Форекс Работа с корзинами валютных пар на рынке Форекс

В статье рассматриваются вопросы о том, как разбить валютные пары по группам - корзинам; как получить данные о состоянии таких корзин (например, перекупленности и перепроданности); какие индикаторы могут предоставить такие данные; наконец, о том, как можно применить полученную информацию в практическом трейдинге.

Текстовые файлы для хранения входных параметров советников, индикаторов и скриптов Текстовые файлы для хранения входных параметров советников, индикаторов и скриптов

В статье рассмотрены вопросы хранения динамических объектов, массивов и других переменных в качестве свойств советников, индикаторов и скриптов в текстовых файлах. Они служат удобным дополнением к функционалу стандартных средств, предлагаемых языками MQL.