この章では、C++における「動的なメモリ確保と解放」について学びます。プログラムの実行中に必要なだけメモリを確保したり、不要になったら解放することで、柔軟なメモリ管理が可能になります。
| 種類 | 宣言例 | 確保のタイミング | 解放方法 |
|---|---|---|---|
| 静的確保 | int a; |
コンパイル時 | 自動 |
| 動的確保 | int* p = new int; |
実行時(プログラム中) | delete p; |
new で確保し、delete で明示的に解放する必要がある// 16_new_delete_basic.cpp
#include <iostream>
using namespace std;
int main() {
int* p = new int; // int型のメモリを1つ確保
*p = 100; // 値を代入
cout << *p << endl; // 値を表示
delete p; // メモリを解放
return 0;
}
// 16_new_delete_array.cpp
#include <iostream>
using namespace std;
int main() {
int size;
cout << "配列のサイズを入力: ";
cin >> size;
int* arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i * 10;
for (int i = 0; i < size; i++) cout << arr[i] << " ";
cout << endl;
delete[] arr; // 配列は delete[] で解放
return 0;
}
delete ではなく必ず delete[] を使ってください。間違えるとメモリリークや未定義動作の原因になります。
| 項目 | new / delete |
vector |
|---|---|---|
| サイズの可変性 | 自分で確保し直す必要あり | .push_back()で簡単に拡張可能 |
| 解放 | 明示的に delete 必要 |
自動で解放される |
| 安全性 | ミスするとメモリリーク | 安全で例外処理も対応 |
| 推奨度 | 低(必要なときのみ) | 高(基本的にこちらを使う) |
vector を使えば十分。new は特別な場合にだけ使う。
次のコードの出力は何ですか?
int* p = new int[3]; p[0] = 10; p[1] = 20; p[2] = 30; cout << p[1]; delete[] p;
new int[3] で3要素の配列を動的確保し、p[0]=10, p[1]=20, p[2]=30 と代入。p[1] は 20 です。動的確保した配列は通常の配列と同じ添字でアクセスできます。
動的確保した配列の解放に正しい構文はどれですか?
new[] で確保した配列は必ず delete[] で解放します。delete(角括弧なし)は単一オブジェクト用です。free() はC言語の関数でC++の new には使えません。
次のコードにはどんな問題がありますか?
int* p = new int[5]; for (int i = 0; i < 5; i++) p[i] = i; // delete[] を忘れた return 0;
new で確保したメモリは delete しない限り解放されません。プログラム終了時にOSが回収することもありますが、長時間動作するプログラムや繰り返し確保するループでは深刻なメモリリークになります。
動的確保と vector の比較として正しい説明はどれですか?
vector はスコープを抜けると自動でメモリを解放(デストラクタが呼ばれる)するため、メモリリークのリスクがありません。要素数も実行時に push_back() で動的に追加できます。
new で生成したオブジェクトはポインタで受け取ります。
ポインタ経由でメンバ変数・メンバ関数にアクセスするときは、
ドット(.)の代わりに ->(アロー演算子) を使います。
| 書き方 | 使う場面 | 例 |
|---|---|---|
obj.method() | 通常のオブジェクト(スタック上) | enemy.attack(); |
ptr->method() | ポインタ(newで確保したオブジェクト) | enemy->attack(); |
// 例:->演算子の使い方
#include <iostream>
using namespace std;
class Enemy {
public:
string name;
void attack() {
cout << name << " が攻撃した!" << endl;
}
};
int main() {
Enemy obj; // スタック上のオブジェクト
obj.name = "スライム";
obj.attack(); // . でアクセス
Enemy* ptr = new Enemy(); // ヒープ上のオブジェクト
ptr->name = "ゴブリン";
ptr->attack(); // -> でアクセス
delete ptr;
return 0;
}
new して作ったオブジェクトには ->、普通に宣言したオブジェクトには . を使う。
// main.cpp
#include <iostream>
using namespace std;
int main() {
int size;
cout << "配列のサイズを入力: ";
cin >> size;
int* arr = new int[size];
for (int i = 0; i < size; i++) arr[i] = i * 10;
for (int i = 0; i < size; i++) cout << arr[i] << " ";
cout << endl;
delete[] arr;
return 0;
}
16_01_DynMem の main.cpp をコピーして 16_02_DynMemMod に貼り付け、次の変更を加えてみましょう:
delete[] でメモリを解放する// main.cpp
#include <iostream>
using namespace std;
int main() {
int n;
cout << "人数を入力: ";
cin >> n;
int* scores = new int[n];
int total = 0;
for (int i = 0; i < n; i++) {
cout << i + 1 << "人目の点数: ";
cin >> scores[i];
total += scores[i];
}
cout << "合計: " << total << endl;
cout << "平均: " << (double)total / n << endl;
delete[] scores;
return 0;
}
new は動的にメモリを確保し、delete で解放するdelete[] を忘れずにvector を使う方が安全で簡単