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

 

MT5ビルド1940

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

void OnStart()
{
A a;

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

どちらの場合もコンパイルされます。

A m_A[2]; // и так

A* m_A[2]; // и так

最初のケースでは、削除されない(新規に作成される)オブジェクトが出力され、メモリリークが発生します

1 undeleted objects left
1 object of type A left
24 bytes of leaked memory

OK、手動で解放...すると、コンパイラは(突然)配列に非ポインタが含まれていることに気づきました:"オブジェクトポインタが期待されています"

delete m_A[1]; // Если 'm_A' массив объектов -> object pointer expected

よし、ポインタ配列として宣言してみよう。

A* m_A[2];

コンパイルができる!これは私にとってニュースでした。では、MQLにポインターはあるのかないのか?なぜなら,charや intなどの組み込み型では

'*' - pointer cannot be used

しかし、今回はランタイムになります。

m_A[0] =a; // получаем: "invalid pointer access"

原理的には論理的である)。

この結果については、いくつかの疑問があります。

1.C/C++のポインターのように主要な機能を果たさないのであれば、MQLのこれらのサブポインターは何のためにあるのでしょうか?

2.MTはメモリがどれだけ漏れたか正確なバイト数まで知っていて、自動的に解放できるのなら、なぜdeleteで遊ぶ必要があるのでしょうか?

 

削除する場合は、ポインターの種類を 確認する必要があります。1つのオブジェクトは新規作成され、削除する必要があります(例では2番目)、もう1つは自動作成され(例では1番目)、それは自動的に削除されます。

 
Dmitry Fedoseev:

削除する場合は、ポインターの種類を 確認する必要があります。一方のオブジェクトはnewで作成され、削除する必要があります(例では2番目)、もう一方は自動です(例では1番目)、それは自動的に削除されるでしょう。

つまり、最初のケースではm_A[0] スタックオブジェクト'a'のコピーではなくそのローカルオブジェクトへのPOINTER_AUTOMATIC タイプの ポインタを 含みますが、これは (他の関数から呼ばれた場合) 関数を終了するとPOINTER_INVALID タイプになってしまいますか?

 
では、一般的にはどうかというと、コンパイラはPOINTER_AUTOMATIC 型のポインタをPOINTER_DYNAMIC 型のポインタに保存したり、その逆を許したりしています。
 
SemenTalonov:

つまり、最初のケースではm_A[0] スタックオブジェクト'a'のコピーではなくそのローカルオブジェクトへのPOINTER_AUTOMATIC 型の ポインタと なり、そのポインタは(他の関数から呼ばれた場合)関数を終了するとPOINTER_INVALID 型になるのでしょう?

どんなものでも、使い方を間違えれば「インバリッド」になる。ポイントは、POINTER_INVALIDではなく、自動的に作成されたオブジェクトも自動的に削除されることです。

いかなる場合も、ここでオブジェクトのコピーを作成することは一切できない。ポインターは単なるポインターであり、オブジェクトがどこにあるかを示す番号を持つ変数、この場合はオブジェクト "a "である。つまり、「a」というオブジェクトを「a」で参照してもいいし、「m_A[0]」でやってもいい、2種類のオブジェクトではなく、1つのオブジェクトなんですね。

原理は簡単で、オブジェクトを作成したのはあなた自身であり、それを削除するのもあなた自身です。自分が作ったのでないなら、放っておけばいい。それくらい簡単なことなのです。

 
SemenTalonov:
一般に、この問題は次のように聞こえます。コンパイラは、POINTER_DYNAMIC 型のポインタをPOINTER_AUTOMATIC 型のポインタに保存すること、または その逆を許可しています。

その逆も然り。POINTER_DYNAMIC 型のポインタは、POINTER_AUTOMATIC型のポインタに割り当てる ことができる。しかし、これは正しくて良いことです。多くの可能性が広がります。

 

何が問題なのか理解できないのですが?

オブジェクトの配列を取り、その最初の要素をスタック上に生成されたオブジェクトと等価にするのです。同時に、コピー演算子を宣言せずに !これはもうエラーです。

まあ、オブジェクトが非常に単純であることを考慮すると、デフォルトでコピーコンストラクタがそこに生成されます。そして、その配列には、作成されたオブジェクトの コピーが含まれています。

質問には問題ありません。

1.ポインターはその役割を果たし、個人的には配列へのポインターしか懐かしくありません。

MQLは、マークしていないものを削除してはいけないのです。Dmitriyが言ったように、「オブジェクトを作って、それを削除する」というのは正しい。 私は、私が望むときではなく、アセンブラが望むときにオブジェクトが削除されるC#の「ゴミ収集器」のような慣習が好きではありません。

 
Georgiy Merts:

何が問題なのか理解できないのですが?

オブジェクトの配列を取り、その最初の要素をスタック上に生成されたオブジェクトと等価にするのです。同時に、コピー演算子を宣言せずに !これはもうエラーです。

まあ、オブジェクトが非常に単純であることを考慮すると、デフォルトでコピーコンストラクタがそこに生成されます。そして、その配列には、作成されたオブジェクトの コピーが含まれています。

それこそコピーを期待していたのに・・・。デフォルトのコピーコンストラクタはエラーにならない。

しかし、Dmitryは、新しいオブジェクトがメモリに割り当てられ、POINTER_AUTOMATIC 型のポインタが返され、 コピーは存在しないとしています。

みんな自分なりにMQLのクセを理解している)

 
SemenTalonov:

そんなコピーを期待していたのですが...。デフォルトのコピーコンストラクタはエラーにならない。

しかし、Dmitryは、新しいオブジェクトがメモリに割り当てられ、POINTER_AUTOMATIC 型のポインタが返されると言っています。

みんな自分なりにMQLのクセを理解している)

エラーにならない」とはどういう意味ですか?定義されていない演算子を使用しています。

しかし、このオブジェクトの中に他のサブオブジェクトがあり、初期化が必要であったり、このオブジェクト自体がリソースリクエストを必要とする場合はどうでしょうか?

宣言されていないものは使えないようですね。

"Quirks "は見ませんでしたが、Dimitriは「オブジェクトのコピーがない」ことについて間違っていると思います。その理由は、やはり未宣言文が使用されているからです。

 

オブジェクトのコピーはどこから来るのか?ポインターのコピーはそうだが、同じオブジェクトを指している。

 
Georgiy Merts:

エラーにならないとはどういうことですか?定義されていない演算子を使用しています。

私が言いたいのは、明示的にコピーコンストラクタを宣言しても、このテストでは何も変わらないということです。

どうして当たり前のことがわからないんだ...。

ポインターはオブジェクトの配列の 項目に、オブジェクトはポインターの配列の項目に...本当に大丈夫なんでしょうか?

最初のケースでは、配列はオブジェクトへのポインタになり、2番目のケースでは、コピーコンストラクタが動作するはずですが、これらの操作はどのように同等になるのでしょうか?

理由: