ArrayRemove関数の働き・役割
ArrayRemove関数は、配列内の特定のインデックスから指定した数の要素を削除するために使用されます。この関数は、動的配列や固定サイズの配列に対して適用可能ですが、削除後の挙動に違いがあります。動的配列の場合、配列のサイズが調整されますが、静的配列(固定サイズの配列)はサイズはそのままで残りの要素が前方に移動されます。
ArrayRemove関数の引数について
ArrayRemove関数は、3つの引数を受け取ります。引数の構成は以下の通りです。
第1引数:array[]
任意の型の配列を指定します。削除操作の対象となる配列です。この関数は配列を直接操作するため、削除後の配列に反映されます。この配列は静的配列、または変更可能な配列でなければなりません。指標バッファや固定サイズの配列の場合、制約があります。
第2引数:start
削除を開始するインデックスです。この値は配列内の位置を指定し、0から始まるインデックスで表されます。startの値が配列の範囲外である場合、関数はエラーを返します。
第3引数:count
削除する要素の数を指定します。この引数には初期値(デフォルト値)としてWHOLE_ARRAYが設定されており、この場合は指定したインデックスから配列の最後までのすべての要素が削除されます。具体的な数を指定する場合は、その数だけ要素が削除されます。ただし、countの値が配列の要素数を超える場合はエラーとなります。
ArrayRemove関数の戻り値について
ArrayRemove関数は、削除操作が成功した場合にt
rueを返します。何らかの理由で操作が失敗した場合はfalse
が返されます。削除が失敗するケースとして、以下のエラーコードが取得される場合があります。
- 5052 – ERR_SMALL_ARRAY
指定したstart
インデックスが配列の範囲を超えている場合に発生します。 - 5056 – ERR_SERIES_ARRAY
指標バッファとして使用されている配列に対して、削除操作を行った場合に発生します。このような配列は端末の実行サブシステムによって管理されており、手動で削除することはできません。 - 4003 – ERR_INVALID_PARAMETER
指定したcount値が不正、または配列のサイズを超えている場合に発生します。 - 4005 – ERR_STRUCT_WITHOBJECTS_ORCLASS
デストラクタを持つ複雑なオブジェクトが含まれている固定サイズの配列に対して削除を試みた場合に発生します。 - 4006 – ERR_INVALID_ARRAY
デストラクタを持つオブジェクトまたはクラスオブジェクトを含む固定サイズの配列に対して削除操作を試みた際に発生します。
ArrayRemove関数を使う際の注意点
ArrayRemove関数は、固定サイズの配列に使用すると、配列のサイズは変わらず、削除された要素の後にある部分が前に物理的にコピーされます。このコピーでは、コンストラクタやコピー演算子は呼び出されません。デストラクタを持つオブジェクトを含む配列には適用できません。
SetIndexBuffer関数でインジケータバッファとして指定された配列にも使用できません。インジケータバッファは端末のサブシステムが管理しているため、エラーが発生します。
削除開始のインデックスが配列の範囲外である場合や、削除する要素数が多すぎる場合もエラーとなります。
コンストラクタとコピー演算子とは
コンストラクタとは、クラスのインスタンス(オブジェクト)が生成される際に、自動的に呼び出される特別な関数です。コンストラクタは、オブジェクトの初期化を行います。例えば、オブジェクトの内部状態(メンバ変数)に初期値を設定するために使われます。
コピー演算子は、あるオブジェクトから別のオブジェクトへコピーする際に呼び出される演算子です。オブジェクトの深いコピー(メモリやポインタの管理が必要な場合など)を行う際に重要です。コピー演算子が定義されていない場合、コンパイラが自動的に生成する浅いコピー(メモリ上の値のコピー)が使われます。
コンストラクタとコピー演算子の具体例
class MyClass {
public:
int* data;
// コンストラクタ
MyClass(int value) {
data = new int(value); // メモリを確保して初期化
Print("コンストラクタが呼び出されました");
}
// コピー演算子
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this; // 自分自身のコピーを避ける
delete data; // 古いデータの削除
data = new int(*other.data); // 新しいメモリを確保してコピー
Print("コピー演算子が呼び出されました");
return *this;
}
// デストラクタ
~MyClass() {
delete data;
Print("デストラクタが呼び出されました");
}
};
上記のコードでは、MyClass
クラスにはコンストラクタ、コピー演算子、デストラクタが定義されています。コンストラクタはオブジェクトが生成された時に呼び出され、メモリの確保などを行います。コピー演算子は、他のオブジェクトから値をコピーする際に使用され、デストラクタはオブジェクトが破棄されるときにメモリを解放します。
ArrayRemove関数では、配列内のオブジェクトが物理的にコピーされます。これは、オブジェクトのメモリ上のデータがそのままコピーされることを意味します。このコピー処理では、コンストラクタやコピー演算子は呼び出されません。
たとえば、先ほどの例のようにメモリを管理するオブジェクトを扱う場合、コンストラクタやコピー演算子を通じてメモリの確保やコピーが行われることが期待されます。しかし、ArrayRemove関数の物理的コピーでは、こうした手順がスキップされてしまうため、メモリリークやデータの不整合が発生するリスクがあります。そのため、デストラクタを持つオブジェクトを含む配列に対して、この関数を適用することは避ける必要があります。
このような場合、オブジェクトのメモリ管理が正しく行われないことがあるため、特に注意が必要です。
ArrayRemove関数を使ったサンプルコード
以下は、ArrayRemove関数を使用して、配列から指定した要素を削除するサンプルコードです。
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 静的配列を宣言し、初期化
int array[10]; // サイズ10の静的配列
for(int i=0; i<10; i++)
{
array[i] = i; // 各要素に0から9までの値を設定
}
//--- 要素を削除する前に配列の内容を表示
Print("Array before removing elements:");
ArrayPrint(array); // 配列の内容をエキスパートログに出力
//--- 配列のインデックス4から2つの要素を削除
ArrayRemove(array, 4, 2);
//--- 要素を削除した後に配列の内容を表示
Print("Array after removing elements:");
ArrayPrint(array); // 削除後の配列をエキスパートログに出力
}
実行結果:
int array[10]
:サイズ10の静的配列を宣言し、0から9までの値を設定しています。- ArrayPrint(array):配列の内容をエキスパートログに出力します。
- ArrayRemove(array, 4, 2):インデックス4から2つの要素(4と5)を削除します。削除後、インデックス6以降の要素が前に移動され、残った要素(8, 9)が配列末尾に複製されます。
サンプルコード解説
OnStart関数は、MQL5のスクリプトプログラムが実行される際に自動的に呼び出される関数です。この関数内で配列の初期化や操作が行われます。
まず、サイズ10の静的配列arrayを宣言しています。この配列の各要素には、forループを用いて0から9までの値が順番に設定されています。iがインデックスとなり、array[i] = iによって対応する値が代入されます。
配列から要素を削除する前にArrayPrint関数を使用して配列の内容をエキスパートログに出力しています。この出力により、配列の状態を確認できます。Print関数はログメッセージを表示する関数で、この場合「Array before removing elements:」というメッセージが出力されます。
ArrayRemove関数を使用して、インデックス4から始まる2つの要素を削除しています。この場合、インデックス4の要素である「4」と、その次の要素である「5」が削除されます。削除後の配列の構造が物理的に変更され、インデックス6以降の要素が前に移動します。つまり、6と7がインデックス4と5に移動し、配列の後半にはもともとあった値が残ります。
ArrayRemove関数の実行後に、再度ArrayPrint関数で配列の内容をエキスパートログに出力します。削除後の配列の状態が確認でき、「Array after removing elements:」というメッセージと共に新しい配列の内容が表示されます。
結果として、削除前の配列は以下のようになります: 0 1 2 3 4 5 6 7 8 9
インデックス4と5にあった要素(4と5)が削除された後の配列は以下のように変化します: 0 1 2 3 6 7 8 9 8 9
この結果から、削除された要素の後にある要素が前に移動し、配列の末尾には残りの要素が複製されていることがわかります。
ArrayRemove関数を使ってEAを作る際のアイディア
ArrayRemove関数は、配列から特定の要素を削除するための便利な機能です。この関数をEA(:エキスパートアドバイザー)の開発に活用することで、特定の条件に基づいてリストやデータセットから要素を動的に管理することが可能です。以下はいくつかの応用アイディアです。
トレード履歴の管理
EAが複数のトレードを実行している場合、過去のトレードデータを配列に保存し、特定の条件(例えば、一定期間が経過したトレードや利益確定済みのトレードなど)に基づいて古いデータを配列から削除することが考えられます。これにより、配列のデータ量を常に最適化し、不要なデータを除外することで、メモリ効率を向上させることができます。
注文キューの動的管理
取引戦略によっては、エントリー条件が整ったときに複数の注文を発行し、それらを配列に格納することがあります。このとき、ArrayRemove関数を使用して、配列内の不要な注文(条件が変わってキャンセルされた注文や、すでに実行された注文)を削除し、最新の注文状態だけを管理することが可能です。これにより、注文の監視や管理が簡潔になります。
シグナルリストのフィルタリング
EAで複数のインジケータ(指標)を使用して取引シグナルを発生させる場合、シグナルごとに配列を作成し、過去のシグナルや不要なシグナルを削除する際にArrayRemove関数を使うことができます。これにより、シグナルの管理が柔軟になり、リアルタイムにシグナルの有効性を維持したまま、古いシグナルを動的に除去できます。
エラー処理やログの最適化
EAが動作する際にエラーログやアクティビティログを配列に蓄積することがあります。不要なエントリーや古いエントリーを一定条件で削除することで、ログの最適化を行い、過度にログデータが蓄積されるのを防ぐことが可能です。特定のエラーが発生した際にそのログを削除したり、重要なログのみを保持したりする管理も有効です。
これらのアイディアを活用することで、ArrayRemove関数を使った配列の動的な要素削除が、EAのパフォーマンスや効率を向上させる一助となります。