基本から理解するC++スマートポインタ
本来手動でメモリ管理しなければならない動的なオブジェクトを、スコープによって自動でメモリ管理するもの。
オブジェクトのライフタイム
プログラム実行中に生成されるオブジェクト(Object)には、必ずどこかの記憶域(Storage)が割り当てられます[1]。記憶域が有効である期間のことを記憶域期間(Storage duration)と呼びます[1][2][3]。オブジェクトのライフタイムは、この記憶域期間によって決まります[1]。
記憶域の期間と、そこに存在しているオブジェクトのライフタイムは必ずしも一致しないことに注意してください[1]。たとえば、型がクラスではないオブジェクト(int値やbool値)のライフタイムは、その記憶域が終わるときと一致しますが、型がクラスであるオブジェクトは、デストラクタが呼ばれた時がライフタイムの終わりであり、記憶域はそのまま残り続けることは許されます[1]。また記憶域が確保されても(ここから記憶域の期間が始まる)、その上でオブジェクトがコンストラクトされるまではオブジェクトのライフタイムは始まりません(std::vector::reserve()がよい例です)[4]。
[TODO: 図が欲しい]
C++で記憶域期間は以下4つに分けられます。
- Static storage duration
ThreadまたはDynamicな記憶域期間を持たず、ローカルでない変数は、静的記憶域期間(Static storage duration)を持ちます[1]。この期間は、プログラムの終了まで続きます。
- Thread storage duration
- Automatic storage duration
ブロックスコープ内の変数で、
static
,thread_local
,extern
で宣言されていない変数は、自動記憶域期間(Automatic storage duration)を持ちます[1]。メモリは、実行がブロックに入ったときに割り当てられ、ブロック終了時に割り当てを解除されます[5]。{ // これらオブジェクトは, このブロックスコープを抜けると自動的に記憶域の割り当てを解除されます。 int i, j, k; Resource resource; }
- Dynamic storage duration
以上をみると、プログラマが明示的に削除しないといけないのは、動的記憶域期間をもつオブジェクトであることがわかります。
スコープとオブジェクトのライフタイムの関係
スコープとは
コンピュータサイエンスにおいてスコープという用語には、二つの意味があります[6]。一つは、名前バインディング(変数などの、実体に名前を関連付けること)のスコープ、もう一つは、が有効なプログラムの一部分を指すソースコードの一部(テキスト領域)という意味でのプログラムの一部、もう一つは、実行時間(実行中の時間帯)の一部
動的なオブジェクトのメモリを自動管理する
動的記憶域期間を持つオブジェクトは、C++の仕様で自動で解放されることはありません。必ずdelete式で明示的に開放する必要があります。
そこで、この動的なオブジェクトをラップしてdeleteする責任を持たせたものがスマートポインタです。スマートポインタは、自身が削除されるときに保持している動的なオブジェクトを必要ならば解放します。スマートポインタ自体を、自動で解放される記憶域期間を持った変数たとえば自動変数として使うことで、動的なオブジェクトをまるで自動変数として扱うことができます。
{ // 自動記憶域期間でresourceオブジェクトを生成 Resource resource; // ... } // ブロックを抜けると, resourceオブジェクトは自動で解放 { // 動的記憶域期間でresourceオブジェクトを生成 Resource *resource = new Resource; // ... // ブロックを抜ける前に手動でdelete delete resource; } { // resourceオブジェクトをスマートポインタで管理 std::unique_ptr<Resource> resource(new Resource); // ... } // ブロックを抜けると, resourceオブジェクトは自動で解放
所有権
unique_ptr
shared_ptr
動的確保した記憶域のライフタイム
プログラム実行中にnew式で動的に作られた領域のことを動的領域(dynamic storage)と呼びます[1][2]。動的領域は、delete式で明示的に開放する必要があります。動的領域が作られてから削除されるまでの期間をdynamic storage durationと呼びます[1]。
- Static storage duration
- Thread storage duration
- Automattic storage duration
C++仕様書6.7.5.4によると
ブロックやパラメータスコープに属し、static、thread_local、externのいずれにも明示的に宣言されていない変数は、自動的に保存期間が設定されます。これらの実体の保存期間は、それらが作成されたブロックが終了するまで続きます。
- Dynamic storage duration
プログラマは、動的に確保した領域に対して、開放する責任があります。
スコープ
プログラムで要素たとえば、変数、クラス、関数などを宣言するとき、その名前はプログラムのある範囲でしか見ることができません。
- Block scope
- Statement scope
- Namespace scope
- Global namespace scope
- Function parameter scope
- Class scope
- Enumeration scope
- Template parameter scope
参考文献
- ^ a b c d e f g h i j "Working Draft, Standard for Programming Language C++". open-std.org. Retrieved 2022-12-01.
- ^ a b "Storage class specifiers". cppreference.com. Retrieved 2022-12-01.
- ^ "記憶域期間 | Programming Place Plus 用語集". Programming Place Plus. Retrieved 2022-12-03.
- ^ "storage duration vs lifetime". Stack Overflow. Retrieved 2022-12-03.
- ^ "ストレージクラス". Microsoft Learn. Retrieved 2022-12-03.
- ^ "Scope (computer science)". Wikipedia. Retrieved 2022-12-06.
- https://qiita.com/hmito/items/9b35a2438a8b8ee4b5af
- https://www.chromium.org/developers/smart-pointer-guidelines/
- https://www.geeksforgeeks.org/smart-pointers-cpp/
- https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
- https://stackoverflow.com/questions/13852710/single-vs-shared-ownership-meaning
- https://stackoverflow.com/questions/8538165/when-does-an-object-on-the-heap-go-out-of-scope
- https://en.cppreference.com/w/cpp/language/scope
- https://learn.microsoft.com/en-us/cpp/cpp/scope-visual-cpp?view=msvc-170
- https://open-std.org/jtc1/sc22/wg21/docs/papers/2022/n4910.pdf
- https://learn.microsoft.com/ja-jp/cpp/cpp/smart-pointers-modern-cpp?view=msvc-170