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

 
Ilya Malev:

ただ、MCLではC++と同じようにはいきません。ここでは、ポインタは全く別のデータ型ではないので、どちらもオブジェクトであり、変数にはそのハンドルが格納されています。

だろう?

// тот же класс А что был выше

A a; // будет создан автообъект с реальным выделением памяти и инициализацией. 'a' является указателем со статусом POINTER_AUTOMATIC

A* pA; // память под объект не выделена, объекта нет. pA является указателем со статусом POINTER_INVALID или POINTER_DYNAMIC?

しかし、ポインタが生成された後にどのようなステータス(POINTER_INVALIDまたはPOINTER_DYNAMIC)になるかは、はっきりとは言えません。理論的には、newから アドレスを取得するまではPOINTER_INVALIDであるべきです。

 
Ilya Malev:

つまり、宣言する

そして、まったく同じ「自動オブジェクト」を持つことになりますが、それを自分で 削除する必要があります。

それはオートじゃない...。

 
SemenTalonov:

生成後のポインタがPOINTER_INVALIDとPOINTER_DYNAMICの どちらのステータスになるかはわかりません。考え方としては、newが アドレスを取得するまではPOINTER_INVALIDであるべきです。

その通り、ステータスはPOINTER_INVALIDに なります。しかし、変数 a と pA は同じ型である。aだけが定数で、コンストラクタは生成時に、デストラクタはブロックから離れる時に呼ばれますが、pAはランダムにアクセスされ、コンストラクタとデストラクタは任意に呼び出されます。

を付けずに宣言した変数は、特別な仕掛けをしないとPOINTER_INVALID状態になりません。これも、変数の型が違うからではなく、コンパイラがコンストラクタとデストラクタの呼び出しをうまく制御して、別の値を代入することを禁じているためです。

また、変数は基本的に同じ型なので、変数を通してクラスメソッドにアクセスするロジックが異なることはありません。

 
Ilya Malev:

これは正しく、ステータスはPOINTER_INVALIDに なります。しかし、変数 a と pA は同じ型である。a のみ定数で、生成時にコンストラクタ、ブロックからの終了時にデストラクタが呼ばれ、pA はランダムアクセスで、コンストラクタとデストラクタがランダムに呼ばれます。

だから、すべての悩みは、それらを区別 する必要があることから来るだけなのです。つまり、ポインターはより責任ある姿勢(DYNAMICな もの)を要求されるのです。

 
SemenTalonov:

区別 する必要があるからに他なりません。つまり、ポインターはより責任ある姿勢(DYNAMICな もの)を要求されるのです。

私の考えでは、OOPのポイントは、あくまでもオブジェクトの参照を受け渡し、格納し、その中に異なる振る舞いをするクラスを書くことができることだと考えています。ポリモーフィズムに 触れることなく「自動オブジェクト」への参照を保存し始めると、すでにその区別をすべて失ってしまいます(A&型のユーザ変数が存在しないため)。

 
Ilya Malev:

を付けずに宣言した変数は、特別な仕掛けをしないとPOINTER_INVALIDの状態を 与えられない、これもそうですが、変数の型が違うからではなく、コンパイラがコンストラクタやデストラクタの呼び出しをうまく制御して、違う値を代入することを禁じているためです。

その通りです。自動オブジェクトポインタはその状態が変化しないが、POINTER_DYNAMIC ポインタはプログラム実行中のどの瞬間にも非有効に なる可能性がある。その理由は、そのような出来事の可能性そのものよりも、重要なことなのです。

 
SemenTalonov:

その通りです。自動オブジェクトポインタは状態が変化しませんが、POINTER_DYNAMIC ポインタはプログラム実行中に無効と なる可能性があります。その理由は、そのような出来事の可能性そのものよりも、重要なことなのです。

これには、安全で優れた治療法があります。

class A{~A(){}};

void OnStart()
 {
  A*a=new A;
  delete a; // oops =))
 };
まあ、プログラマはオブジェクトの寿命の時間や変数へのアクセス方法自体に気をつけるべきで、よく設計されたアーキテクチャはコードを書いてから1、2年後のエラーを最小限に抑えることができると思うのですが......。
 
実際、オブジェクトの寿命は、そのオブジェクトへの「生きている」ポインタの寿命と一致しなければなりません。もちろん、POINTER_DYNAMICの動的オブジェクトも中途半端で、配慮のないコーディングではトラブルが発生します。しかし、POINTER_AUTOMATICは、オブジェクトを適切に処理するために必要なスケーラビリティも与えてくれません。ブロックから抜けるときに、オブジェクトが生成された自動変数以外にオブジェクトへのポインタが生成されなかったら、オブジェクトを削除する、みたいなことが必要です。参照が現在のブロックの外側で受信された場合、これらの参照がまだ生きている間はオブジェクトを削除しないでください。そうすれば、スケーラビリティも出てくるし、コーダーが勝手に削除をずっと見ていることもなくなるし......。(例えば、今、A* a = new A; と書いて、再び a = new A とすると、最初のオブジェクトは永遠に失われ、プログラム終了時にログにメモリリークエラーが出ることが保証されます。そして、その時、有名なコードオプティマイザはどこを見ているのでしょうか)。
 
Ilya Malev:
基本的に、オブジェクトの寿命は、そのオブジェクトへの「生きている」ポインタの寿命に対応しなければならない。もちろん、mkl POINTER_DYNAMIC 型のダイナミックオブジェクトも半ばオプション的なものであり、コーディングがあまり効率的でない場合には悩みの種になる。しかし、POINTER_AUTOMATICは、オブジェクトを適切に処理するために必要なスケーラビリティも与えてくれません。ブロックから抜けるときに、オブジェクトが生成された自動変数以外にオブジェクトへのポインタが生成されなかったら、オブジェクトを削除する、みたいなことが必要です。参照が現在のブロックの外側で受信された場合、これらの参照がまだ生きている間はオブジェクトを削除しないでください。そうすれば、スケーラビリティも出てくるし、コーダーが勝手に削除をずっと見ていることもなくなるし......。(例えば、今、A* a = new A; と書いて、再び a = new A とすると、最初のオブジェクトは永遠に失われ、プログラム終了時にログにメモリリークエラーが 出ることが保証されます。そして、有名なコードオプティマイザはどこを見ているのだろうか)

それもかなりのサプライズでしたね。結局、逃げたバイトをすべて正確に知っているが、それを解放しようとはしない。では、今のところディノスポは全く見ていないのですね。これは、要求されたメモリと最後に解放されたメモリの差を単純に数えたものです。

また、ライフタイムや空・消失ポインタは問題のひとつに過ぎません。ポインタからオブジェクトへの暗黙の変換に関連する問題を議論する前に、それはクラッシュです)誤って(例えば、コンパイラがそのようなコードをコンパイルすることを許可していないはず)、期待ポインタの代わりに、ポインタによってオブジェクトのコピーを取得するかもしれません、それは順番にどこにも指さないかもしれません)。さて、比較演算については、すでにご自身で書かれていますね。そこもすべて暗黙の了解です。

 
SemenTalonov:

1.それもかなりのサプライズでしたね。結局、逃げたバイトをすべて正確に知っていて、それを解放しようとはしない。では、今のところディノスポは全く見ていないのですね。要求されたメモリと最後に解放されたメモリの差をカウントしているだけです。

また、ライフタイムや空・消失ポインタは問題のひとつに過ぎません。

1.そうではなく、動的オブジェクトへの単純なGCを書くことは開発者にとって簡単なことなのですが、コーダーが自分のプログラムに不具合があることを知ることができるように、わざとこのようなメッセージを残しているのだそうです。なぜなら、彼らのダイナミック・オブジェクトは、そのような半C#(私は専門家ではないが、聞いたところによると)-まるでオブジェクトが同じように振る舞う(ポインターはないが、すべてオブジェクトである)、そしてそのための凝ったサブシステムは開発されなかったからである。

2.もちろん、オブジェクト変数が同じ型であれば(つまり、自動的に、あるいは独立して削除されるのではなく、参照がなくなったときに内蔵のゴミ収集器によって削除される)、それらへの参照はすべてまったく同じになるはずです。