動的メモリ管理
[前の講義で]、変数[と]配列[はどちらも]スタック(Stack)[上に割り当てられる]――[サイズは固定]で、関数が[終了すると解放される]。
[しかし、もし][不確定な数の][データ]を保存する必要がある場合([例えば、ユーザーが]1000 [個の整数]を入力する[が、]コンパイル時には[その数が]わからない場合など)、[その際には]動的メモリ[割り当て]——ヒープ(Heap)[上に]メモリを割り当てる必要があります。
1. スタックとヒープ
(1) 1.1 [2種類の]メモリ[領域]
| [比較] | スタック(Stack) | ヒープ(Heap) |
|---|---|---|
| [割り当てのタイミング] | コンパイル時[確定] | 実行時[確定] |
| [大小] | [固定](コンパイル時[確定]) | [可変](実行時[割り当て]) |
| [解放のタイミング] | [自動解放](function[終了]) | [手動解放]([使用] delete) |
| [効率] | [高] | [低] |
| [適用シーン] | ローカル変数、配列 | [動的なサイズのデータ] |
(2) 1.2 [生活における]クラス[比]
| [生活シーン] | 番組[での対応] |
|---|---|
| [ファストフード店]([固定メニュー]、[注文したらすぐに持ち帰り]) | stack |
| [ビュッフェ]([好きなだけ取って食べていい]) | heap |
2. 新規 [和] 削除
(1) 2.1 [使用] 新規 [割り当て] メモリ
[文法]:
▶ サンプル 2: 動的メモリ[管理] (難易度 ⭐)
* = new ;
例:
#include iostream
int main() {
// points int
int* p = new int; // p heap's int
*p = 5; // int
std::cout << "*p = " << *p << std::endl; // 5
return 0;
}
💡 [要点]: new [返されるのは]ポインタ——[ヒープ上に割り当てられた]メモリを[指す]もの。
(2) 2.2 [使用] メモリの削除 [解放]
[文法]:
delete ;
例:
#include iostream
int main() {
int* p = new int;
*p = 5;
std::cout << "*p = " << *p << std::endl;
delete p; // ✅ heap's
p = nullptr; // ✅:pointer
return 0;
}
💡 [黄金律]: new [と] delete [必ずペアで現れる]――new [があれば] delete [もある]。
(3) 2.3 [削除] すると [メモリリーク] が発生する
エラー例:
#include iostream
void foo() {
int* p = new int;
*p = 5;
// ❌ write delete p;
} //,p, int ()
int main() {
for (int i = 0; i < 1000000; i++) {
foo(); // 4
}
//,
return 0;
}
💡 メモリリーク: ヒープ[に割り当てられた]メモリ[が解放されず]、[アクセスすることもできない]([それを指していた]ポインタ[が破棄されてしまった]ため)。
3. [動的]配列
(1) 3.1 [使用] new [割り当て]array
[文法]:
* = new ;
例:
#include iostream
int main() {
int n;
std::cout << ":";
std::cin >> n;
// points n int
int* arr = new int[n];
// ...
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
// output
for (int i = 0; i < n; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
// (: delete, delete)
delete arr;
return 0;
}
💡 [重要]: [配列]を[解放]するには、delete([角括弧付き])を使用し、deleteは[使用しない]!
(2) 3.2 new [和] delete [ペアでなければならない]
| [割り当て] | [解放] |
|---|---|
new int |
delete p; |
new int[10] |
delete p; |
エラー例:
int* p = new int[10];
delete p; // ❌:Using delete p;
4. [懸]ヌルポインタ(ダングリングポインタ)
(1) 4.1 [悬]nullポインタとは何か?
[懸]nullポインタとは、[解放済みの]メモリ[を指す]ポインタのことです。
#include iostream
int main() {
int* p = new int(5);
delete p; // ...
// ❌:p Nowpointer
std::cout << *p << std::endl; //!output,
return 0;
}
💡 [解決方法]: [解放後、直ちに] nullptr に設定する:
delete p;
p = nullptr; // ✅
5. 演習:[動的]配列[ソート]
▶ サンプル 1: [配列]を使って[選択ソートを実装する] (難易度 ⭐⭐)
#include iostream
// ...
void selectionSort(int* arr, int n) {
for (int i = 0; i < n - 1; i++) {
int minIdx = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIdx]) {
minIdx = j;
}
}
// ...
int temp = arr[i];
arr[i] = arr[minIdx];
arr[minIdx] = temp;
}
}
int main() {
int n;
std::cout << ":";
std::cin >> n;
int* arr = new int[n]; // points
std::cout << "..." << n << ":" << std::endl;
for (int i = 0; i < n; i++) {
std::cin >> arr[i];
}
selectionSort(arr, n); // ...
std::cout << ":" << std::endl;
for (int i = 0; i < n; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
delete arr; // ...
arr = nullptr;
return 0;
}
[動作結果]:
5:
5 3 1 4 2:
1 2 3 4 5
6. [よくある]エラー
(1) 6.1 [重複] 削除
エラー例:
int* p = new int(5);
delete p;
delete p; // ❌:(Definebehavior)
[修正]: [解放後、直ちに] nullptr に設定(delete nullptr [は安全です])。
delete p;
p = nullptr;
(2) 6.2 [削除] delete
エラー例:
int* arr = new int[10];
// ❌ write delete arr;
[結果]: メモリリーク。
❓ よくある質問
📖 まとめ
- スタック:コンパイル時[割り当て]、[自動解放]、[サイズ固定]
- ヒープ:実行時[割り当て]、[手動解放](
delete)、[サイズ可変] new[割り当て]メモリ,delete[解放]メモリnew[割り当て]配列,delete[解放]配列- メモリリーク:[忘れてしまった]
delete,[深刻な結果を招く] - [注意]nullポインタ:[解放済みの]メモリを指しており、[危険]
📝 練習問題
-
初心者(難易度 ⭐): [使用]
new[1つを割り当てる]double,[値]value3.14を割り当て,出力[後に解放]。 -
中級(難易度 ⭐⭐): [ユーザーに]
nを入力させ、newを使用してnのサイズを持つint配列を動的に割り当て、n個の整数を入力させ、[最大値] を求めた後、[配列を解放]する。 -
上級(難易度 ⭐⭐⭐): [動的メモリ]を用いて、[「動的」]配列クラスを[実装する]([後で学ぶ]クラスについて、[ここではとりあえず]structを使用する):
-
[包含]:
int* data([ヒープ上の]配列へのポインタ)、int size([現在のサイズ])、int capacity([容量]) -
[実装]
push_back関数:[もし]size == capacityなら、[より大きな]メモリを割り当て直し(new[より大きな]配列を[コピーし]、[古いものを解放する]) -
[テスト]:[追加] 100 [個の要素]
-
新規 [割り当て]ヒープメモリ、[返却]ポインタ
-
[解放された]メモリを削除し、[割り当てられた]新しいメモリを削除する
-
new [割り当て]array、delete [解放]array
-
メモリリーク:new [忘れてしまった] delete
-
[割り当て失敗]:new [例外をスロー] std::bad_alloc 例外
7. 🚀 次は
[動的メモリ[割り当て]を学びました]。[次は] ポインタ[と]参照[の]実践[総合演習]([第]27[課])—— [総合的な]演習を通じて、[これまでに学んだすべての知識を]定着させましょう!



