2-3. 動的メモリ

公開日: 21:58 2. 応用編/2-3. 動的メモリ

C++においてどのように動的メモリが実際に働くか充分に理解することは、優秀なプログラマになるのに不可欠です。C++プログラム内のメモリは2つに分かれています。 

  • スタック : 関数内で宣言されたすべての変数はスタックからメモリを取ります。 
  • ヒープ : これはプログラムが未使用のメモリであり、プログラム実行時に動的にメモリをを確保するときに使われます。 

多くの場合、実行時に決定される要求メモリサイズや、定義した変数が特定の情報を保存するのにどのくらいのメモリを必要とするかは事前に認識していません。

C++では特別な演算子を使い、与えられた型の変数を、実行時のヒープ内にメモリを割り当てることができます。演算子は実行時に決まる割り当てられた空間へのアドレスを返します。この演算子をnewと呼びます。

動的に割り当てたメモリが必要なくなった場合、delete演算子を使い、new演算子によって割り当てられたメモリを開放することができます。

newとdelete

new演算子を使い任意のデータ型の動的なメモリ割り当てを行う一般的な構文は次のようになります。
new data-type;

ここでは、data-typeは組み込みデータ型や、配列またはユーザ定義されたクラスや構造体を含むデータ型を取り得ます。例えばdouble型へのポインタを定義し、実行時にメモリを割り当てるよう要求します。これを実現するにはnew演算子を使って次のように記述します。
double* pvalue = NULL; // NULLで初期化されたポインタ
pvalue = new double;   // 変数にメモリを要求

メモリに空きがない場合、メモリは正常に割り当てられないでしょう。そのため、new演算子がNULLを返すか、適切な動作をとるか次のように確認することは良いトレーニングとなります。
double* pvalue = NULL;
if( ! ( pvalue = new double ) )
{
    cout << "Error : out of memory." << endl;
    exit( 1 ):
}

C言語のmalloc()関数はC++にも有りますが、使わないことが推奨されています。newがmalloc()関数より優れている主な点は、newはただメモリを割り当てるだけでなく、C++の主要目的であるオブジェクトを構築するということです。

いかなるときでも、動的に割り当てられた変数が必要なくなった時、次のようにdelete演算子を使いメモリを開放することができます。
delete pvalue;   //pvalueが指すメモリを開放

次の例で上で述べた概念と形式を用いて、newとdeleteがどのように動くか確認してみましょう。
#include <iostream>
using namespace std;

int main ()
{
   double* pvalue  = NULL; // NULLで初期化されたポインタ
   pvalue  = new double;   // 変数に割り当てを要求
 
   *pvalue = 29494.99;     // 割り当てられたアドレスに値を保存
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // メモリを開放

   return 0;
}
上のコードをコンパイルし実行すると、次のような結果となります。
Value of pvalue : 29495

配列への動的なメモリ割り当て

20文字の文字列のようなcharの配列にメモリを割り当てたいとします。上で使ったものと同じ構文を用いて次のようにメモリを動的に割り当てることができます。
char* pvalue  = NULL;   // NULLで初期化されたポインタ
pvalue  = new char[20]; // 変数にメモリを割り当て

作成した配列を削除するには次のようになります。
delete [] pvalue;        // pvalueの指す配列を削除

次のnew演算子を使った一般的な構文は、多次元配列を割り当てることができます。
double** pvalue  = NULL;     // NULLで初期化されたポインタ
pvalue  = new double [3][4]; // 3x4の配列にメモリを割り当て

しかしながら、多次元配列のメモリを開放する構文は、上のものと同じままです。
delete [] pvalue;        // pvalueの指す配列を削除

オブジェクトへの動的なメモリ割り当て

オブジェクトは単一のデータ型と違いがありません。コンセプトを明確にするため、次のオブジェクトの配列を使うコードを見てみましょう。
#include <iostream>
using namespace std;

class Box
{
   public:
      Box() { 
         cout << "Constructor called!" <<endl; 
      }
      ~Box() { 
         cout << "Destructor called!" <<endl; 
      }
};

int main( )
{
   Box* myBoxArray = new Box[4];

   delete [] myBoxArray; // 配列を削除

   return 0;
}

4つのオブジェクトを割り当てると、コンストラクタが4回呼ばれ、同様にこれらのオブジェクトを削除すると、デコンストラクタも同じ回数呼ばれます。 上のコードをコンパイルし実行すると、次の結果が得られます。
Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!
  • ?±??G???g???[?d????u?b?N?}?[?N???A

0 件のコメント :

コメントを投稿