newとdelete

メモリの動的確保

C言語ではメモリの確保にはmalloc関数とfree関数を使用していました。
C++ではメモリの動的確保手段が構文に組み込まれ、動的確保が簡単にできるようになっています。

new演算子

new演算子は、指定したデータのメモリを確保し、そのポインタを返します。


#include <iostream>

int main()
{
    int buf = 100;
    
    //これはできない
    //int nums[buf];

    int *nums = new int[buf];

    for (int i = 0; i < buf; i++)
    {
        nums[i] = i;
    }

    std::cout << nums[0] << std::endl;
    std::cout << nums[50] << std::endl;
    std::cout << nums[99] << std::endl;

    //newしたものはdeleteする
    delete[] nums;

    std::cin.get();
}

8行目のように、通常の配列では変数を配列のサイズに指定することはできません。
new演算子を使用すれば、変数の値でメモリを確保することができます。

new演算子で返ってくるのはポインタですから、受け取り側もポインタ変数にします。
受け取った後は通常の配列と同じように使用することができます。

サンプルコードでは配列を生成していますが、単体の変数を生成する場合は「new int()」と、データ型に続いて丸括弧を記述します。
引数に数値を指定すれば、その値で初期化されます。


//単体(値は0)
int *num = new int();

//単体(値は10)
int *num = new int(10);

//配列(要素数10)
int *nums = new int[10];

delete演算子

動的確保したメモリは、必要がなくなれば解放する必要があります。
メモリを解放するにはdelete演算子を使用します。

newで確保したメモリは、必ずdeleteで解放するのがルールです。
deleteしないままだとメモリが確保されたままになってしまい、メモリ不足の原因となります。

C言語のmalloc関数と同じく、プログラムの終了と同時に確保したメモリは自動的に解放されますので、サンプルコードのような単純なものであればdeleteしなくても問題は発生しません。

delete演算子の書き方には少し注意点があります。


int *a = new int();
delete a;

//配列形式でnewした場合は
//配列形式でdeleteする
int *b = new int[1];
delete[] b;

int *c = new int[10];
delete[] c;

配列としてメモリを確保した場合には「delete[] ポインタ変数名」という形式にする必要があります。
newで作成した配列に対してdelete([]なし)を行った場合の動作は不定で、バグの原因となるおそれがあります。

メモリを確保しポインタを返す関数

deleteするまではメモリ上に領域は確保されたままですから、関数内でメモリを確保してそのポインタを返すことができます。
これはC言語のmalloc関数で確保したメモリを「自動解放されない領域」として使ったのと同じです。


#include <iostream>

//指定のサイズの配列をポインタで返す関数
int *createArray(int size, int n = 0)
{
    int *arr = new int[size];
    for (int i = 0; i < size; i++)
    {
        arr[i] = n;
    }
    return arr;
}

int main()
{
    int *nums = createArray(100, 1);

    std::cout << nums[0] << std::endl;
    std::cout << nums[50] << std::endl;
    std::cout << nums[99] << std::endl;

    delete[] nums;

    std::cin.get();
}

普通に関数内で配列を宣言した場合は、関数を抜けた時に関数内で宣言した配列の寿命も尽きるので、関数外からアクセスすることはできなくなります。
しかしnew演算子でメモリを確保した場合は勝手に消去されないので、ポインタを受け取るようにすれば外部からでもアクセスが可能になります。

ただし、そのメモリは後で自分で解放する必要があります。
メモリ管理の事を考えなければならないのが面倒なので、C++ではこういった使い方はあまり見かけません。
その代わりにvectorなどのコンテナ型や、自作のクラスを使用します。
(クラスについては別途詳しく説明します)

new、deleteの注意点

new演算子、delete演算子はほとんどmalloc関数、free関数の代用として使用することができます。
しかしmalloc関数との互換性があるわけではありません。
malloc関数で確保したメモリをdelete演算子で解放しようとしたり、new演算子で確保したメモリをfree関数で解放しようとしたりしてはいけません。

また、new演算子はmalloc関数にはない機能もあります。
これは後に説明するクラスという機能に関係しますので、その時に改めて説明します。