コンテンツにスキップ

newとdelete#

C/C++の学習において難しいポイントの一つに、動的メモリの確保と解放があります。

C++では、メモリの確保と解放を行うために、newdeleteというキーワードを使います。

C言語でよく使われるmallocと比べると、確保手順が煩雑ではないため、こちらを推奨しています。


newとdelete#

newは、メモリを確保するためのキーワードです。そして、deleteは、メモリを解放するためのキーワードです。

ここでは、2回int型の配列を確保するコードを見てみましょう。

deleteのタイミングを変えています。

#include <cstdio>

int main(void)
{
    int size = 10;
    int* ptr1 = new int[size];
    for (int i = 0; i < 10; i++)
    {
        ptr1[i] = i;
        printf("@%p: %d\n", &ptr1[i], ptr1[i]);
    }

    delete ptr1;
    printf("\n@%p: %d\n\n\n", &ptr1[1], ptr1[1]);

    int* ptr2 = new int[size];
    for (int i = 0; i < 10; i++)
    {
        ptr2[i] = i*10;
        printf("@%p: %d\n", &ptr2[i], ptr2[i]);
    }

    // delete ptr1;
    delete ptr2;
    return 0;
}

newは、int[size]のように、配列のサイズを指定することができます。

また、deleteを使うことで、メモリを解放することができます。(deleteで解放した後のデータを見ると、0または不定の値が入っています。)


実行結果1#

先ほどのプログラムの実行結果です。

@0x560c59fd7eb0: 0
@0x560c59fd7eb4: 1
@0x560c59fd7eb8: 2
@0x560c59fd7ebc: 3
@0x560c59fd7ec0: 4
@0x560c59fd7ec4: 5
@0x560c59fd7ec8: 6
@0x560c59fd7ecc: 7
@0x560c59fd7ed0: 8
@0x560c59fd7ed4: 9

@0x560c59fd7eb4: 0


@0x560c59fd7eb0: 0
@0x560c59fd7eb4: 10
@0x560c59fd7eb8: 20
@0x560c59fd7ebc: 30
@0x560c59fd7ec0: 40
@0x560c59fd7ec4: 50
@0x560c59fd7ec8: 60
@0x560c59fd7ecc: 70
@0x560c59fd7ed0: 80
@0x560c59fd7ed4: 90

同じ番地に異なる値を格納していることがわかります。また、deleteを使用することで、内部の値が0に戻っていることも確認できました。

このように、newで確保したメモリはdeleteで解放することで、同じリソースを再利用することができます。

実行結果2#

次は、delete ptr1;の実行場所を変更して最終行付近に移しました。

    }

    delete ptr1;
    delete ptr2;
    return 0;

実行結果は、以下のようになります。

@0x557129ab3eb0: 0
@0x557129ab3eb4: 1
@0x557129ab3eb8: 2
@0x557129ab3ebc: 3
@0x557129ab3ec0: 4
@0x557129ab3ec4: 5
@0x557129ab3ec8: 6
@0x557129ab3ecc: 7
@0x557129ab3ed0: 8
@0x557129ab3ed4: 9

@0x557129ab3eb4: 1


@0x557129ab42f0: 0
@0x557129ab42f4: 10
@0x557129ab42f8: 20
@0x557129ab42fc: 30
@0x557129ab4300: 40
@0x557129ab4304: 50
@0x557129ab4308: 60
@0x557129ab430c: 70
@0x557129ab4310: 80

みなさんの直感の通り、ptr1とptr2の位置が変わっています。

大きなデータを扱う時などのメモリが枯渇する可能性がある場合には、動的メモリの適切な確保と解放が重要になります。

ただし、ポインタを用いた直接的なメモリアクセスは間違ったアドレスへのアクセスを検知できないため、非常に危険です。(例:範囲外の配列値にもアクセスできる)