動的メモリ (new/delete)
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 14/104。
ポインタと参照を理解したところで、これらを動的メモリ割り当てで活用してみましょう。new 演算子と delete 演算子を使用すると、実行時にヒープ上にオブジェクトを作成したり破棄したりできます。
new を使用してメモリを割り当て、そのポインタを取得します:
int* num = new int; // 単一の整数を割り当てる
*num = 42; // ポインタを介して値を代入する
Player* player = new Player("Hero"); // オブジェクトを割り当てるメモリを解放するために、すべての new には対応する delete が必要です:
delete num; // 単一のオブジェクトを解放する
delete player; // デストラクタを呼び出し、その後メモリを解放する配列の場合は、new[] と delete[] を使用します:
int* scores = new int[5]; // 5つの整数の配列を割り当てる
scores[0] = 100;
delete[] scores; // 配列を解放する - 角括弧に注意してください!避けるべき一般的な間違い:
// メモリリーク - deleteを忘れた
int* ptr = new int(10);
ptr = new int(20); // 最初の割り当てへのアクセスを失った!
// ダングリングポインタ - delete後に使用
delete ptr;
*ptr = 5; // 未定義の動作!
// 不一致なdelete
int* arr = new int[10];
delete arr; // 間違い!delete[]であるべき削除した後は、誤った再利用を避けるためにポインタを nullptr に設定してください。手動のメモリ管理はエラーが発生しやすいため、モダンなC++ではスマートポインタが好まれます。これについては次に詳しく見ていきます。
チャレンジ
簡単new と delete を使用した動的メモリ割り当てを実演する、シンプルなメッセージ保存システムを構築しましょう。
コードを整理するために、2つのファイルを作成します。
MessageBox.h: メッセージの配列を動的に管理するMessageBoxクラスを定義します。このクラスには以下のものを含める必要があります。- 動的に割り当てられた文字列配列へのプライベートポインタ
- 現在のメッセージ数を追跡するプライベートな整数
- 最大容量を格納するプライベートな整数
- 容量を受け取り、
new[]を使用して配列を割り当てるコンストラクタ delete[]を使用してメモリを適切に解放し、"MessageBox destroyed"と出力するデストラクタ- 空きがある場合にメッセージを追加し、成功した場合は
true、満杯の場合はfalseを返すaddMessage(string msg)メソッド - 格納されている各メッセージをそれぞれの行に出力する
printAll()メソッド
main.cpp: 入力から容量の値とメッセージの数を読み取ります。次に、その数だけメッセージ文字列を読み取ります。newを使用してヒープ上にMessageBoxを作成し、すべてのメッセージを追加してprintAll()を呼び出し、その後MessageBoxを適切に削除してメモリを解放します。
入力形式は以下の通りです:
- 1行目:容量(整数)
- 2行目:追加するメッセージの数(整数)
- 続く行:1行につき1つのメッセージ
注意:すべての new には対応する delete が必要であり、すべての new[] には対応する delete[] が必要です。削除した後は、ポインタを nullptr に設定するのが良い習慣です。
#include "MessageBox.h" を使用して、main.cpp にヘッダーファイルをインクルードしてください。
チートシート
new を使用して、ヒープ上にメモリを動的に割り当て、そのポインタを取得します:
int* num = new int; // Allocate single integer
*num = 42; // Assign value through pointer
Player* player = new Player("Hero"); // Allocate objectすべての new には、メモリを解放するための対応する delete が必要です:
delete num; // Free single object
delete player; // Calls destructor, then frees memory配列の場合は、new[] と delete[] を使用します:
int* scores = new int[5]; // Allocate array of 5 integers
scores[0] = 100;
delete[] scores; // Free array - note the brackets!避けるべき一般的な間違い:
// Memory leak - forgot to delete
int* ptr = new int(10);
ptr = new int(20); // Lost access to first allocation!
// Dangling pointer - using after delete
delete ptr;
*ptr = 5; // Undefined behavior!
// Mismatched delete
int* arr = new int[10];
delete arr; // Wrong! Should be delete[]削除した後は、誤った再利用を避けるためにポインタを nullptr に設定してください。
自分で試してみよう
#include <iostream>
#include <string>
#include "MessageBox.h"
using namespace std;
int main() {
int capacity;
int numMessages;
// 容量とメッセージの数を読み取る
cin >> capacity;
cin >> numMessages;
cin.ignore(); // 数値の後の改行をクリアする
// TODO: new を使用してヒープ上に MessageBox を作成する
// TODO: すべてのメッセージを読み取り、MessageBox に追加する
for (int i = 0; i < numMessages; i++) {
string message;
getline(cin, message);
// メッセージを MessageBox に追加する
}
// TODO: printAll() を呼び出してすべてのメッセージを表示する
// TODO: メモリを解放するために MessageBox を削除する
// 削除した後はポインタを nullptr に設定することを忘れないこと
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス