MQL5 Компилятор не различает класс и указатель на него - страница 3

 
SemenTalonov:

Бинго!

SemenTalonov 2019.01.10 07:36    EN
Тогда в общем случае, проблема звучит как: компилятор позволяет, в указатель типа POINTER_AUTOMATIC сохранить указатель типа POINTER_DYNAMIC, и наоборот.

Да не совсем бинго. Для простых объектов работает присваивание оператором =. Не баг точно.

 
SemenTalonov:

...

SemenTalonov 2019.01.10 07:36    EN
Тогда в общем случае, проблема звучит как: компилятор позволяет, в указатель типа POINTER_AUTOMATIC сохранить указатель типа POINTER_DYNAMIC, и наоборот.

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

 


С каких времен определены (вопрос разработчикам)

void A::operator =( const A& );
void A::operator =( const A* );

и как они работают? Следующий компилируемый код выглядит бредово

    A* b = NULL;    
    m_A[1] = b;    


И здесь ситуация не ясна

A* m_A[2];

void OnStart()
{
A a;

    m_A[0] =a;  // Почему это работает?
    m_A[0] =&a; // Когда должно работать только это?
}
 
Dmitry Fedoseev:

Да не совсем бинго. Для простых объектов работает присваивание оператором =. Не баг точно.

Вот-вот, это самый главный момент.

Лично я считаю, что нельзя использовать оператор присваивания для объектов, если этот оператор не определен явно, даже если объекты простые. Еще как-то можно согласиться на присваивание простых структур. Но классы, в которых обязательно вызывается конструктор (как минимум, неявно) - присваиваться могут только явно определенными операторами.

На мой взгляд, это было сделано для упрощения жизни новичкам.

 
Georgiy Merts:

Вот-вот, это самый главный момент.

Лично я считаю, что нельзя использовать оператор присваивания для объектов, если этот оператор не определен явно, даже если объекты простые. Еще как-то можно согласиться на присваивание простых структур. Но классы, в которых обязательно вызывается конструктор (как минимум, неявно) - присваиваться могут только явно определенными операторами.

На мой взгляд, это было сделано для упрощения жизни новичкам.

И сложные удобны - без этого нельзя вернуть MqlTradeRequest, например. И в структурах также обязательно вызывается конструктор.

 

Есть версия что MQL это такой очень обрезанный C#. Исходя из этого, становится понятно поведение MQL компилятора в данном случае. Ведь в C# классы всегда размещаются в куче, следовательно:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
class A
{
public:
    int iValue;
};
//......................
A m_A[2];

void OnStart()
{
    // Разместили A в куче, указатель на A передали в m_A[1]
    m_A[1] = new A();
    // Разместили A на стеке...
    A a;
    // А вот фиг вам! ля-ля-ля;) Там вам не тут. 'a' - класс и размещается в куче. Указатель на него передается внутреннему сборщику мусора
    // А раз так, то теперь он AUTOMATIC и к нему нельзя применить delete, т.к. внутренний сборщик мусора его удалит сам 
    
    // скопировали указатель a в массив
    m_A[0] = a;
}
//+------------------------------------------------------------------+

Теперь разберемся с массивом m_A. Раз m_A массив классов, а классы размещаются всегда в куче, следовательно нет необходимости указывать является ли массив m_A массивом указателей или массивом самих объектов, т.к. для классов всегда работает только первый вариант. Раз m_A всегда массив указателей, то в MQL сделана поблажка: в нем можно не указывать хранит ли он ссылочные типы или значимые. Следовательно A* m_A[2] == A m_A[2]. Аминь.

 
Vasiliy Sokolov:

Есть версия что MQL это такой очень обрезанный C#. Исходя из этого, становится понятно поведение MQL компилятора в данном случае. Ведь в C# классы всегда размещаются в куче, следовательно:

Теперь разберемся с массивом m_A. Раз m_A массив классов, а классы размещаются всегда в куче, следовательно нет необходимости указывать является ли массив m_A массивом указателей или массивом самих объектов, т.к. для классов всегда работает только первый вариант. Раз m_A всегда массив указателей, то в MQL сделана поблажка: в нем можно не указывать хранит ли он ссылочные типы или значимые. Следовательно A* m_A[2] == A m_A[2]. Аминь.

Неверный вывод. m_A - массив объектов, а не указателей. И эти объекты полностью уничтожаются. Не уничтожается new A.

class A
{
public:
    int iValue;
    
  ~A()
  {
    Print(__FUNCSIG__);
  }
};
//......................
A m_A[2];

void OnStart()
{
A a;
A* b = new A;

    m_A[0] =a;  // копирование объекта, а не указателя
    m_A[1] = b; // копирование объекта, а не указателя
    
  // по выходу уничтожится три объекта
  delete b; // а так - четыре.
}
 
fxsaber:

Неверный вывод. m_A - массив объектов, а не указателей. И эти объекты полностью уничтожаются. Не уничтожается new A.

Хороший пример. Хм. Тогда будем думать дальше.

 

пхах)) я вообще в шоке с этого

A m_A[2];

void OnStart()
{
A a;
A* b = new A();

    printf("SizeOf 'a' object: %i SizeOf pointer 'b' to object: %i", sizeof(a), sizeof(b));
    
    a =b;
    b =a;
    
    m_A[0] = a;
    m_A[1] = b;
}
SizeOf 'a' object: 20 SizeOf pointer to 'b' object: 8
 
SemenTalonov:

пхах)) я вообще в шоке с этого

А что не так? В одном случае объект, в другом случае указатель.