個人的には、このような場合、オブジェクトのInit()関数を使います。
まず、配列を作成し、配列内のすべてのオブジェクトに対してInit()関数を呼び出し、そこですべてのパラメータを設定できるようにします。
別の関数で初期化すると、オブジェクトの再初期化が可能になり、コンストラクタで初期化すると、オブジェクトの再初期化ができなくなる。
もう1点。オブジェクトの配列はポインタで作成するのがよいでしょう。そうしないと、スタック・メモリに配列ができてしまい、非常に小さくなってしまいます。
Strategy2 *pZ[]; if (ArrayResize(pZ, 10) != 10) { Alert("Memory allocation error"); return; } for (int i = 0; i < 10; ++i) { pZ[i] = new Strategy2("EURUSD"); if (CheckPointer(pZ) == POINTER_INVALID) { Alert("Class instantiation error"); return; } }
問題ではないし、潜在的な問題であることは確かです。MTのメモリ操作のクセが出ただけです。ここでは、静的な配列を示します。
#define ARRAY_SIZE int(60000000) class Test { public: int nA; double fB; datetime dtC; Test(void) : nA(0) , fB(1.0) , dtC(__DATETIME__) { }; }; Test classTest[ARRAY_SIZE]; // 'classTest' - global variables section is too large void OnStart() { }
そして、こちらがダイナミックアレイ。
#define ARRAY_SIZE int(60000000) class Test { public: int nA; double fB; datetime dtC; Test(void) : nA(0) , fB(1.0) , dtC(__DATETIME__) { }; }; Test *pClassTest[]; void OnStart() { if (ArrayResize(pClassTest, ARRAY_SIZE) != ARRAY_SIZE) { Alert("Not enought memory"); return; } for (int i = 0; i < ARRAY_SIZE; ++i) { pClassTest[i] = new Test(); if (CheckPointer(pClassTest[i]) == POINTER_INVALID) { Alert("Class instantiation error"); return; } } for (int i = 0; i < ARRAY_SIZE; ++i) delete pClassTest[i]; }
この場合、すべてコンパイルして動作します。
問題ではないし、ましてや潜在的な問題でもない。MTのメモリ操作のクセが出ただけです。ここでは、静的な配列を示します。
そして、こちらがダイナミックアレイ。
この場合、すべてがコンパイルされ、動作します。
スタックと何の関係があるんだ?最初のケースでは、静的に(コンパイル時に)ヒープに大きなメモリブロックを確保しようとしたため、コンパイラに額を蹴られたことになります。なぜなら、それだけのメモリを確保できるかどうか、現実にはよくわからないからです。
2つ目のケースでは、すでに実行時に大きなメモリチャンクを割り当てていることになります。そして、割り当てられるかどうかは、プログラムがすでにマシンの特定のリソース(メモリ)を使って動作しているため、すぐにわかるようになっています。
また、ポインターは何の関係があるのでしょうか?mqlの配列には、コンパイル時に定義されるものと、ダイナミックに定義されるものがあります。ポインタ * だけでなく、通常のクラスフィールドも動的配列を指すことができる。だから、ここでポインターを使うのは絶対に正当化できない。
ポインタ、クラス、マクロなど、コードの印象がおかしく、何が起こっているのか全く理解できない。
問題ではありませんし、ましてや潜在的な問題でもありません。MTのメモリ操作のクセが出ただけです。ここでは、静的な配列を示します。
そして、こちらがダイナミックアレイ。
この場合、すべてコンパイルして動作します。
間違った例では、何も言わないコンパイラの制限で、開発者がそう決めただけです。
もし、2つのバージョンがあって、一方は大きな静的配列、もう一方は小さな静的配列で、なんと、プログラムが動作したとき、一方では、例えば、関数を再帰的に呼び出すときに問題が発生し、もう一方では、同じ条件下で問題が発生しなかったとします。その時に、結論を出すことができるのです・・・生絞りジュースの害について)))
スタックと何か関係があるのでしょうか?最初のケースでは、静的に(コンパイル段階で)ヒープに大きなメモリブロックを確保しようとしたため、コンパイラに頭を蹴られて当然です。なぜなら、現実世界では、それだけのメモリを確保できるかどうかがまったくわからないからです。
2つ目のケースでは、すでに実行時に大きなメモリチャンクを割り当てていることになります。そして、割り当てられるかどうかは、プログラムがすでにマシンの特定のリソース(メモリ)を使って動作しているため、すぐにわかるようになっています。
また、ポインターは何の関係があるのでしょうか?mqlの配列には、コンパイル時に定義されるものと、ダイナミックに定義されるものがあります。ポインタ * だけでなく、通常のクラスフィールドも動的配列を指すことができる。だから、ここでポインターを使うのは絶対に正当化できない。
ポインタ、クラス、マクロなど、コードの印象がおかしく、何が起こっているのか全く理解できない。
この例を少し変えて、ローカルに宣言し、それほどひどくない数値を入れると、コンパイラは何が問題なのかを直接教えてくれる。
#property strict #define ARRAY_SIZE int(140000) class Test { public: int nA; double fB; datetime dtC; Test(void) : nA(0) , fB(1.0) , dtC(__DATETIME__) { }; }; void OnStart() { Test classTest[ARRAY_SIZE]; // the size of local variables is too large }レナーテに反論することがあれば、どうぞご自由に。
- 2014.02.08
- www.mql5.com
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
こんな授業を作っています。
今度は、オブジェクトの配列を呼び出したい。
コンストラクタにグローバルレベルのパラメータがある場合、オブジェクトの配列を素早く作成するにはどうしたらよいでしょうか。
例えば?コンストラクタを変更して先にオブジェクトを作成し、OnInitでオブジェクトをシンボルに置き換えるにはどうすればいいのでしょうか?
もっと簡単な方法があるのでは?