new演算子とは?
new演算子は、MQL5プログラム内で新しいオブジェクトを動的に作成するために使用される演算子です。主にクラスオブジェクトのインスタンスを生成する際に利用されます。
new演算子を用いることで、必要なタイミングでメモリを確保し、オブジェクトを生成することができます。これにより、柔軟で効率的なメモリ管理が可能となります。
通常のインスタンス作成では、メモリはコンパイル時に確保されますが、new演算子を使用すると、実行時に必要な分だけメモリが確保されます。これにより、プログラムの実行中にメモリを効率的に利用することができます。通常のインスタンス作成では、事前に確保したメモリ量が不足したり、逆に使わないメモリが無駄になる可能性があります。new演算子を使うことで、こうした不具合を回避できます。
new演算子の基本構文
new演算子の基本構文は、次のように記述します。
ClassName *object_name = new ClassName(constructor_arguments);
ここで、ClassNameは生成したいクラスの名前を示し、object_nameは新しいオブジェクトへのポインタです。constructor_argumentsは、そのクラスのコンストラクタに渡す引数です。
コンストラクタとは?
コンストラクタは、クラスのインスタンスが生成される際に自動的に呼び出される特別な関数です。コンストラクタは、オブジェクトの初期化を行います。例えば、変数の初期値を設定したり、必要なリソースを確保したりします。
使用例
次に、具体的な使用例を示します。
// SampleClassというクラスを定義
class SampleClass
{
private:
int number;
string text;
public:
// コンストラクタ
SampleClass(int num, string txt)
{
number = num;
text = txt;
}
// メソッド
void Display()
{
Print("Number: ", number);
Print("Text: ", text);
}
};
// SampleClassの新しいインスタンスを作成
SampleClass *sampleObject = new SampleClass(10, "example");
// オブジェクトのメソッドを呼び出す
sampleObject.Display();
この例では、SampleClassというクラスを定義し、その中にコンストラクタとDisplayというメソッドを持たせています。SampleClassの新しいインスタンスが動的に作成され、ポインタsampleObjectに格納されます。コンストラクタには、整数と文字列が引数として渡されています。
new演算子の注意点
new演算子は、対応するサイズのオブジェクトを自動的に作成し、オブジェクトのコンストラクタを呼び出して作成されたオブジェクトの記述子を返します。失敗した場合、NULLを返します。オブジェクト記述子はメモリアドレスへのポインタではないことに留意すべきです。
※メモリアドレスへのポインタは、メモリ上の特定の位置を直接指し示すものです。一方、オブジェクト記述子は、オブジェクトを操作するための参照情報であり、内部的には異なる仕組みで管理されています。
つまり、オブジェクト記述子は直接メモリアドレスを扱うものではなく、オブジェクトを適切に操作するための間接的な手段を提供します。この違いにより、メモリアドレスと混同しないよう注意が必要です。
new演算子を使用して作成したオブジェクトは、明示的にdelete演算子を使用してメモリを解放する必要があります。これを怠るとメモリリーク(メモリが無駄に消費され続ける問題)が発生します。
また、new演算子はクラスオブジェクトのみに適用でき、構造体には適用できません。さらに、new演算子はオブジェクトの配列作成には使用できません。オブジェクトの配列の作成にはArrayResize関数が使用されます。
公式リファレンスのサンプルコードについて。
MQL5公式リファレンスのnew演算子には以下のようなサンプルコードが掲載されています。
初学者の方がいきなりこのコードを見ても良くわからないと思うので、小分けにして解説していきたいと思います。
//+------------------------------------------------------------------+
//| 図の作成 |
//+------------------------------------------------------------------+
void CTetrisField::NewShape()
{
m_ypos=HORZ_BORDER;
//--- 7 つの可能な図形から 1 つをランダムに選んで作成する
int nshape=rand()%7;
switch(nshape)
{
case 0: m_shape=new CTetrisShape1; break;
case 1: m_shape=new CTetrisShape2; break;
case 2: m_shape=new CTetrisShape3; break;
case 3: m_shape=new CTetrisShape4; break;
case 4: m_shape=new CTetrisShape5; break;
case 5: m_shape=new CTetrisShape6; break;
case 6: m_shape=new CTetrisShape7; break;
}
//--- 描画する
if(m_shape!=NULL)
{
//--- 事前設定
m_shape.SetRightBorder(WIDTH_IN_PIXELS+VERT_BORDER);
m_shape.SetYPos(m_ypos);
m_shape.SetXPos(VERT_BORDER+SHAPE_SIZE*8);
//--- 描画する
m_shape.Draw();
}
//---
}
コード解説その1
void CTetrisField::NewShape()
{
void CTetrisField::NewShape()
は、CTetrisFieldクラスのメンバ関数です。この関数は、CTetrisFieldクラスの一部として、新しいテトリスの形を作成する役割を果たします。CTetrisFieldというクラス名と作用域演算子(::)を使って定義されています。
ただし、公式リファレンスでは肝心要のCTetrisFieldクラス自体が定義されていないので、このコードをコンパイルしてもエラーになってしまう、というそもそもの問題があります。
コード解説その2
m_ypos=HORZ_BORDER;
//--- 7 つの可能な図形から 1 つをランダムに選んで作成する
int nshape=rand()%7;
m_ypos = HORZ_BORDER;
は、おそらくm_yposというメンバ変数にHORZ_BORDERの値を設定しています。これは、新しい図形の初期Y座標を設定するためのものと考えられます。
※サンプルコードにはm_ypos もHORZ_BORDERも他に明示的な宣言記述がない為、「考えられる」という表現になってしまいます。
次に、int nshape = rand() % 7;
は、rand関数を使って0から6までのランダムな整数を生成し、nshapeに格納します。
剰余演算(%)を使用して、rand関数が生成するランダムな整数を0から6の範囲に制限しています。これにより、7つの異なる図形の中からランダムに1つを選択することができます。
剰余演算は、除算の余りを求める演算であり、この場合にはランダムな整数を7で割った余りを計算して、0から6の範囲に収めています。
これにより、7つの可能な図形の中から1つをランダムに選択することができます。これは、新しい図形をランダムに作成するための準備と考えられます。
コード解説その3
この部分では、switch文を使ってランダムに選ばれたnshapeの値に基づき、7つの異なるテトリスの形の中から1つを生成しています。各case演算子で、対応するクラスのインスタンスがnew演算子を使って動的に作成され、それがm_shape
に格納されます。このm_shape
や各CTetrisShape
のクラスは明示されていませんが、ここではそのように想定して解説しています。
switch(nshape)
{
case 0:
m_shape = new CTetrisShape1;
break; // nshapeが0の場合、CTetrisShape1の新しいインスタンスを作成
case 1:
m_shape = new CTetrisShape2;
break; // nshapeが1の場合、CTetrisShape2の新しいインスタンスを作成
case 2:
m_shape = new CTetrisShape3;
break; // nshapeが2の場合、CTetrisShape3の新しいインスタンスを作成
case 3:
m_shape = new CTetrisShape4;
break; // nshapeが3の場合、CTetrisShape4の新しいインスタンスを作成
case 4:
m_shape = new CTetrisShape5;
break; // nshapeが4の場合、CTetrisShape5の新しいインスタンスを作成
case 5:
m_shape = new CTetrisShape6;
break; // nshapeが5の場合、CTetrisShape6の新しいインスタンスを作成
case 6:
m_shape = new CTetrisShape7;
break; // nshapeが6の場合、CTetrisShape7の新しいインスタンスを作成
}
このようにして、ランダムに選ばれた形が動的に生成されます。各CTetrisShape
クラスは、ここでは想定されているものであり、実際のクラス定義はコード全体の他の部分に含まれていると考えられます。
コード解説その4
この部分では、m_shape
がNULLでないことを確認し、新しい図形を描画するための準備をしています。m_shape
の各種メソッド(SetRightBorder
、SetYPos
、SetXPos
、Draw
)を使用して図形の位置と境界を設定し、描画を行います。これらのメソッドやm_shape
自体の定義は確認できませんが、ここではそのように想定して解説しています。
//--- 描画する
if(m_shape != NULL)
{
//--- 事前設定
m_shape.SetRightBorder(WIDTH_IN_PIXELS + VERT_BORDER); // 右の境界を設定
m_shape.SetYPos(m_ypos); // Y座標を設定
m_shape.SetXPos(VERT_BORDER + SHAPE_SIZE * 8); // X座標を設定
//--- 描画する
m_shape.Draw(); // 図形を描画
}
<参照>
sizeof演算子