C++では、明示的なオペレーターnewおよびdeleteを使用してメモリ管理を行い、動的にメモリを割り当てたり解放したりします。しかし、手動管理ではメモリリークや二重解放を引き起こす可能性があります。
C++11標準の登場により、std::unique_ptr、std::shared_ptr、std::weak_ptrなどのスマートポインタが導入されました。これらはオブジェクトのライフサイクルを自動的に管理し、スコープを外れた際にリソースを解放することを保証しており、例外が発生しても安心です。
比較の例:
// 手動でメモリを解放 Foo* ptr = new Foo(); // ... delete ptr; // スマートポインタを使うことでより安全 std::unique_ptr<Foo> ptr2 = std::make_unique<Foo>(); // deleteは必要ありません — unique_ptrがすべてを行います
スマートポインタはメモリリークのリスクを減らし、コードをより安全かつ可読性の高いものにします。
同じポインタに対してdeleteを2回呼び出したらどうなりますか?
回答: 最初のdelete呼び出しの後、メモリはすでに解放されています。再度の呼び出しは未定義の動作を引き起こします(undefined behavior)。例:
Foo* p = new Foo(); delete p; delete p; // エラー!
これを避けるために、解放後にポインタをnullptrに設定してください:
delete p; p = nullptr;
物語
大規模なC++プロジェクトで、開発者は
deleteを使用して動的メモリを手動で解放しており、例外のある関数の複数の分岐から退出する際にポインタを削除することを忘れていました。これにより、負荷テストで発見されたメモリリークが発生しました。
物語
異なるコードの部分間で生のポインタを共有しようとした結果、メモリが二重に解放されることになりました — コードの一部が
deleteを実行し、他の部分に通知していませんでした。結果:プロダクションでsegfaultが発生し、core dumpの分析ですぐに原因がわかりました。
物語
古いプロジェクトを新しいC++標準に移行した後、まだ生のポインタを使用している部分を残し、新しいクラスはすでにスマートポインタを使用していました。リソースの所有権の移動に関するエラーに直面しました:メモリが「二重に」解放されていました — まず手動で、次にスマートポインタのデストラクタによって自動的に解放されていました。