目次 このページのソースコードを表示

基本から理解する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]

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

参考文献

  1. ^ a b c d e f g h i j "Working Draft, Standard for Programming Language C++". open-std.org. Retrieved 2022-12-01.
  2. ^ a b "Storage class specifiers". cppreference.com. Retrieved 2022-12-01.
  3. ^ "記憶域期間 | Programming Place Plus 用語集". Programming Place Plus. Retrieved 2022-12-03.
  4. ^ "storage duration vs lifetime". Stack Overflow. Retrieved 2022-12-03.
  5. ^ "ストレージクラス". Microsoft Learn. Retrieved 2022-12-03.
  6. ^ "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
「https://contentsviewer.work/Master/software/cpp/smart-pointer-essential/article」から取得