スタック vs ヒープメモリ
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 12/104。
C++プログラムは、主に2つのメモリ領域を使用します:スタックとヒープです。オブジェクトがどこに配置されるかを理解することは、効率的でバグのないコードを書くために不可欠です。
スタックは、高速で自動的なメモリです。関数内で宣言された変数はここに配置され、スコープ外になると自動的に破棄されます。
void example() {
int x = 10; // スタック割り当て
Player player; // スタック割り当て - 自動的に破棄されます
} // x と player はここで破棄されますヒープは、手動で管理する、より大きく低速なメモリです。ヒープ上のオブジェクトは、明示的に削除するまで存続します。
void example() {
Player* player = new Player(); // ヒープ割り当て
// player は削除されるまで存在します
delete player; // 手動でのクリーンアップが必要
}主な違い:
| スタック | ヒープ |
|---|---|
| 高速な割り当て | 低速な割り当て |
| 制限されたサイズ | 大容量 |
| 自動クリーンアップ | 手動クリーンアップが必要 |
| 固定サイズのオブジェクト | 動적サイズのオブジェクト |
小さく、短命なオブジェクトにはスタック割り当てを使用します。オブジェクトがスコープを超えて生存する必要がある場合や、サイズが実行時に決定される場合には、ヒープ割り当てを使用します。
ヒープメモリの削除を忘れることは、C++プログラムにおける一般的なバグの原因であるメモリリークを引き起こします。
チャレンジ
簡単オブジェクトがどのように作成され、破棄されるかを追跡するシンプルな Counter クラスを構築することで、スタックメモリとヒープメモリの違いを探ってみましょう。
コードを整理するために、2つのファイルを作成します。
Counter.h: プライベートなname属性(string)を持つCounterクラスを定義します。名前を受け取り"Creating: <name>"と出力するコンストラクタと、"Destroying: <name>"と出力するデストラクタを含めます。カウンターの名前を返すgetName()メソッドを追加してください。main.cpp: スタック割り当てとヒープ割り当ての両方を実演します。入力から名前を読み取り、以下の処理を行います:- その名前を使用して、スタックに割り当てられた
Counterを作成する "HeapCounter"という名前で、ヒープに割り当てられたCounterを作成する- 両方のカウンター名を
"Stack: <name>"および"Heap: <name>"の形式で出力する - メモリリークを防ぐために、ヒープに割り当てられたカウンターを削除(delete)する
- その名前を使用して、スタックに割り当てられた
各オブジェクトを作成および削除するタイミングによって、コンストラクタとデストラクタのメッセージが異なる順序で表示されることを確認してください。スタックオブジェクトは main() が終了すると自動的に破棄されますが、ヒープオブジェクトは明示的に削除する必要があります。
main.cpp で #include "Counter.h" を使用してヘッダーファイルをインクルードしてください。
チートシート
C++プログラムは、主に2つのメモリ領域を使用します。スタックとヒープです。
スタックは高速で自動的なメモリです。関数内で宣言された変数はここに配置され、スコープ外に出ると自動的に破棄されます。
void example() {
int x = 10; // スタック割り当て
Player player; // スタック割り当て - 自動的に破棄される
} // xとplayerはここで破棄されるヒープはより大容量ですが、手動で管理する低速なメモリです。ヒープ上のオブジェクトは、明示的に削除するまで存続します。
void example() {
Player* player = new Player(); // ヒープ割り当て
// playerは削除されるまで存在する
delete player; // 手動でのクリーンアップが必要
}主な違い:
| スタック | ヒープ |
|---|---|
| 高速な割り当て | 低速な割り当て |
| サイズ制限あり | 大容量 |
| 自動クリーンアップ | 手動クリーンアップが必要 |
| 固定サイズのオブジェクト | 動的サイズのオブジェクト |
小さく短命なオブジェクトにはスタック割り当てを使用します。オブジェクトがスコープを超えて存続する必要がある場合や、実行時にサイズが決定される場合にはヒープ割り当てを使用します。ヒープメモリの削除を忘れると、メモリリークが発生します。
自分で試してみよう
#include <iostream>
#include <string>
#include "Counter.h"
using namespace std;
int main() {
// 入力から名前を読み取る
string inputName;
cin >> inputName;
// TODO: inputName を使用してスタック割り当ての Counter を作成する
// TODO: 名前が "HeapCounter" のヒープ割り当ての Counter を作成する
// TODO: スタックカウンターの名前を "Stack: <name>" の形式で出力する
// TODO: ヒープカウンターの名前を "Heap: <name>" の形式で出力する
// TODO: メモリリークを防ぐためにヒープ割り当てのカウンターを削除する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス