Обсуждение статьи "Когда нужно использовать указатели в MQL5"

 

Опубликована статья Когда нужно использовать указатели в MQL5:

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


Автор:  MetaQuotes

 

Исходник в тексте надо бы привести в соответствие с приложенным файлами, в частности в листинге GetCriticalError_Unsafe.mq5 обращение делается к несуществующей переменной status вместо pstatus (как в файле).

А в чем смысл определения собственной переменной type в каждом из классов наследников CShape?

И еще бы хотелось услышать пояснения по такому поводу. При переходе от примера GetCriticalError_OnDemand к GetCriticalError_Unsafe все изменение практически сводилось к замене типа аргумента функции с CHello *pobject на CHello &pobject. При этом вызов функции остался неизменным - туда передавался указатель (CHello *). При этом, по словам автора, "опять получим критическую ошибку. Дело в том, что если объект передается по ссылке, то критическая ошибка возникает еще на стадии вызова функции, в которую передается неинициализированный объект." Но в данном случае в функцию передается указатель, а не ссылка. Возникает вопрос, откуда что берется. Нельзя ли поподробнее осветить правила, используемые MQL5 для неявного приведения указателей в ссылки и обратно? Или ткните место в документации, где это описано. Если б компилятор поддерживал строгую типизацию, то пример просто не скомпилировался из-за отсутствия функции с аргументом необходимого типа.

 

marketeer писал(а) # :

Исходник в тексте надо бы привести в соответствие с приложенным файлами, в частности в листинге GetCriticalError_Unsafe.mq5 обращение делается к несуществующей переменной status вместо pstatus (как в файле).

Спасибо, поправил в статье и в файле.

 
marketeer писал(а) # :

А в чем смысл определения собственной переменной type в каждом из классов наследников CShape?

В принципе, этот член нигде не используется, можно убрать. Теоретически, он может использоваться в потомках для реализации функций, зависящих от типа объекта.
 
marketeer писал(а) # :
И еще бы хотелось услышать пояснения по такому поводу. При переходе от примера GetCriticalError_OnDemand к GetCriticalError_Unsafe все изменение практически сводилось к замене типа аргумента функции с CHello *pobject на CHello &pobject. При этом вызов функции остался неизменным - туда передавался указатель (CHello *). При этом, по словам автора, "опять получим критическую ошибку. Дело в том, что если объект передается по ссылке, то критическая ошибка возникает еще на стадии вызова функции, в которую передается неинициализированный объект." Но в данном случае в функцию передается указатель, а не ссылка. Возникает вопрос, откуда что берется. Нельзя ли поподробнее осветить правила, используемые MQL5 для неявного приведения указателей в ссылки и обратно? Или ткните место в документации, где это описано. Если б компилятор поддерживал строгую типизацию, то пример просто не скомпилировался из-за отсутствия функции с аргументом необходимого типа.
Если явно определена функция, принимающая параметр как указатель, то будет использована именно она. Если такой функции нет, то указатель объекта автоматически будет приведен к ссылке на объект и будет использована функция,принимающая объект по ссылке.
 
Rosh писал(а) # :
В принципе, этот член нигде не используется, можно убрать. Теоретически, он может использоваться в потомках для реализации функций, зависящих от типа объекта.
Я правильно понимаю, что согласно текущему исходнику примера получаются "грабли", что в объекте фигуры конкретного типа существует две переменных type, например, CLine::type помимо CShape::type? По идее должна быть одна - из базового класса.
 
Rosh писал(а) # :
Если явно определена функция, принимающая параметр как указатель, то будет использована именно она. Если такой функции нет, то указатель объекта автоматически будет приведен к ссылке на объект и будет использована функция,принимающая объект по ссылке.
Где-то можно почитать о направлении выполняющихся неявно приведений касательно ссылок и указателей? В частности, обратное преобразование тоже делается - от ссылки к указателю?
 
marketeer писал(а) # :
Где-то можно почитать о направлении выполняющихся неявно приведений касательно ссылок и указателей? В частности, обратное преобразование тоже делается - от ссылки к указателю?
Нет, чтобы получить указаетль объекта -используйтк GetPointer().
Документация по MQL5: Общие функции / GetPointer
Документация по MQL5: Общие функции / GetPointer
  • www.mql5.com
Общие функции / GetPointer - Документация по MQL5
 
marketeer писал(а) # :
Я правильно понимаю, что согласно текущему исходнику примера получаются "грабли", что в объекте фигуры конкретного типа существует две переменных type, например, CLine::type помимо CShape::type? По идее должна быть одна - из базового класса.

Да, Вы правы. В каждом потомке существуют две переменные type, как Вы написали. Так получилось потому что код потомков делался копипастом. Чтобы член базового класса был доступен непосредственно для потомков, его нужно определять со спецификатором protected, либо в базовом классе объявлять публичные get- и set- методы для этого члена.

Например, так:

//+------------------------------------------------------------------+
//|                                             demo_inheritance.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CBase
  {
private:
   int               type;
public:
                     CBase(){type=0;}
   int               GetType(){return(type);}
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CSon: CBase
  {
private:
   int               type;
public:
                     CSon(){type=2;}
   void              PrintType();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CSon::PrintType()
  {
   Print("CSon.type =",type);
   Print("CBase.type =",CBase::GetType());
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   CSon  son;
   son.PrintType();
   int father_type=son.GetType();
  }
//+------------------------------------------------------------------+
 
Цитирую:

"Данный пример является очень простым, найти в нем ошибку не составляет труда. Но если ваша mql5-программа содержит сотни или даже тысячи строк, вылавливание таких ошибок может существенно осложниться. Особенно для тех случаев, когда условия возникновения нештатных ситуаций в поведении программы зависит от непредсказуемых факторов - например, от определенного рыночного рынка."

Это как?  :-)

 
Это когда специфика пары отличается чем то.