MQL5 コンパイラはクラスとそのポインタを区別しない - ページ 3

 
SemenTalonov:

ビンゴ!

SemenTalonov2019.01.10 07:36POINTER_AUTOMATIC 型ポインタに保存したり、 その逆をすることを許可 します。

ビンゴとまではいきませんが。単純なオブジェクトでは、演算子=による代入が機能します。確実にバグではありません。

 
SemenTalonov:

...

SemenTalonov2019.01.10 07:36POINTER_AUTOMATIC 型のポインタをPOINTER_DYNAMIC 型のポインタに保存したり、 その逆を行うことを許可 します。

いいえ、ポインタを自動で代入していないときは、オブジェクト、つまりそのフィールドの値をコピーしています。ただし、単純なオブジェクトに限ります。

 

トレーディング、自動売買システム、ストラテジーテストに関するフォーラム

MQL5 Compilerは、クラスとポインタを区別しない

セメン・タロノフ さん 2019.01.10 04:18

class A
{
public:
    int iValue;
};
//......................
A m_A[2];

void OnStart()
{
A a;

    m_A[0] =a; 
    m_A[1] = new A();
}


いつから定義されたのか(開発者への質問)

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はポインタではなく、オブジェクトの配列です。そして、これらのオブジェクトは完全に破壊されています。破壊されるのは新型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はポインタではなく、オブジェクトの配列です。そして、これらのオブジェクトは完全に破壊されています。破壊されるのは新型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:

ふっふっふ))実はこれ、ショックなんです。

どうしたんですか?一方はオブジェクト、もう一方はポインタです。