問題の歴史:
C++ではメモリ操作が基本的であり、言語は効率性のためにプログラマに完全な制御を提供しています。元々は、ダイナミックメモリと自動メモリ割り当ての領域として「スタック」と「ヒープ」という概念だけが存在しました。
問題:
変数の配置の選択は、その寿命、可用性、メモリの割り当てと解放の速度、さらにリスク(メモリリーク、スタックの破損、フラグメンテーション)を決定します。
解決策:
スタックアロケーションは、寿命がわかっているローカル変数に使用されます。ヒープアロケーションは、ダイナミックな寿命や大きなメモリを必要とするオブジェクトに使用されます。手動でのヒープ管理を最小限にし、スタックを優先し、ダイナミックなメモリに対してスマートポインタを使用することをお勧めします。
コード例:
// スタックアロケーション int a = 5; // ヒープアロケーション int* b = new int(10); // スマートポインタの利用 #include <memory> auto ptr = std::make_unique<int>(15);
関数からローカル変数へのポインタを返した場合、何が起きますか?
未定義の動作が発生します:関数から出るとメモリが「解放され」ます(実際にはスタックはクリアされず、データが上書きされる可能性があります)。
悪いコードの例:
int* foo() { int a = 42; return &a; // これは間違い! }
スタックで割り当てされたメモリは漏れることがありますか?
いいえ、スタックのメモリはスコープを外れると自動的に解放されます — 所謂スタックオーバーフローは発生しますが、リークではありません。
常にdeleteを使用して動的メモリを解放することは十分ですか?
いいえ、見落としたdeleteや二重削除を避けるために、スマートポインタ(std::unique_ptr, std::shared_ptr)がより一般的に使用されます。
ネガティブケース:
開発者がすべての一時オブジェクトに対してnewを使い、解放を忘れた結果、大規模アプリでメモリリークが発生しました。
長所: 最初は迅速で便利 短所: 不安定なプログラム、メモリの増加、クラッシュ
ポジティブケース:
一時オブジェクトや補助オブジェクトに対してローカル変数とスマートポインタを使用する。明示的なdeleteはなく、すべてが自動的に解放されます。
長所: リークの回避、信頼性 短所: モダンなメモリ操作の理解が必要です。