最終更新日時: 2026年02月25日 13時06分35秒 (JST)
Akira Takahashi が更新

履歴 編集

class template
<memory>

# std::shared_ptr(C++11)

    namespace std {
      template <class T>
      class shared_ptr;
    }

## 概要

`shared_ptr`は、指定されたリソースへの所有権(ownership)を共有(share)するスマートポインタである。

複数の`shared_ptr`オブジェクトが同じリソースを共有し、所有者が0人、つまりどの`shared_ptr`オブジェクトからもリソースが参照されなくなると、リソースが自動的に解放される。

### 参照カウント

`shared_ptr`は「参照カウント(reference count)」によって実装される。

`shared_ptr`オブジェクトのコピー構築、コピー代入が行われるとカウントが1増える。デストラクタが実行されるとカウントが1減る。そしてカウントが0になると、自動的に「`delete p;`」が実行され、リソースが解放される。

### スレッド安全性

`shared_ptr`の参照カウンタはスレッドセーフである。つまり、スレッドを跨いで`shared_ptr`をコピーし、リソースを共有することが安全にできる。

非スレッドセーフに参照カウントを増減させる方法はない。シングルスレッドでのパフォーマンスが重要で、スレッドセーフであることによるオーバーヘッドが問題になる場合、ムーブを活用すればパフォーマンスを改善できる。

## メンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ | C++11
`(destructor)` | デストラクタ | C++11
`operator=` | 代入演算子 | C++11
`reset` | 所有権を放棄し、新たな所有権を設定する | C++11
`swap` | 他の`shared_ptr`オブジェクトとデータを入れ替える | C++11
`get` | リソースを取得する | C++11
`operator*` | 間接参照 | C++11
`operator->` | メンバアクセス | C++11
`operator[]` | 添字による要素アクセス | C++17
`use_count` | 所有権を持つユーザー数を取得する | C++11
`unique` | 所有権を持つユーザーが一人だけかを判定する | C++11 C++17から非推奨 C++20で削除
`operator bool` | 有効なリソースを所有しているかを判定する | C++11
`owner_before` | 所有権ベースでの小なり比較を行う | C++11
`owner_equal` | 所有権ベースでの等値比較を行う | C++26
`owner_hash` | 所有権ベースでのハッシュ値を取得する | C++26

## メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`element_type` | 管理するインスタンスの型 C++11 : `T` C++17 : `remove_extent_t<T>` | C++11
`weak_type` | 弱参照ポインタの型`weak_ptr<T>` | C++17

## 非メンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator==` | 等値比較 | C++11
`operator!=` | 非等値比較 | C++11
`operator<=>` | 三方比較 | C++20
`operator<` | 左辺が右辺より小さいかを判定する | C++11
`operator<=` | 左辺が右辺以下かを判定する | C++11
`operator>` | 左辺が右辺より大きいかを判定する | C++11
`operator>=` | 左辺が右辺以上かを判定する | C++11
`swap` | 2つの`shared_ptr`オブジェクトを入れ替える | C++11
`get_deleter` | デリータを取得する | C++11
`operator<<` | ストリームへの出力 | C++11
`static_pointer_cast` | `shared_ptr`の静的キャスト | C++11
`dynamic_pointer_cast` | `shared_ptr`の動的キャスト | C++11
`const_pointer_cast` | `shared_ptr`の`const`修飾キャスト | C++11
`reinterpret_pointer_cast` | `shared_ptr`の再解釈キャスト | C++17
`make_shared` | `shared_ptr`を構築するヘルパ関数 | C++11
`allocate_shared` | アロケータを指定して`shared_ptr`を構築するヘルパ関数 | C++11

## アトミックアクセス(非メンバ関数)

名前 | 説明 | 対応バージョン
--- | --- | ---
`atomic_is_lock_free` | 指定されたオブジェクトがロックフリーに振る舞えるかを調べる | C++11 C++20から非推奨 C++26で削除
`atomic_store` | 値を書き込む | C++11 C++20から非推奨 C++26で削除
`atomic_store_explicit` | メモリオーダーを指定して値を書き込む | C++11 C++20から非推奨 C++26で削除
`atomic_load` | 値を読み込む | C++11 C++20から非推奨 C++26で削除
`atomic_load_explicit` | メモリオーダーを指定して値を読み込む | C++11 C++20から非推奨 C++26で削除
`atomic_exchange` | 値を入れ替える | C++11 C++20から非推奨 C++26で削除
`atomic_exchange_explicit` | メモリオーダーを指定して値を入れ替える | C++11 C++20から非推奨 C++26で削除
`atomic_compare_exchange_weak` | 弱い比較で値の入れ替えを行う | C++11 C++20から非推奨 C++26で削除
`atomic_compare_exchange_strong` | 強い比較で値の入れ替えを行う | C++11 C++20から非推奨 C++26で削除
`atomic_compare_exchange_weak_explicit` | 弱い比較でメモリオーダーを指定して値の入れ替えを行う | C++11 C++20から非推奨 C++26で削除
`atomic_compare_exchange_strong_explicit` | 強い比較でメモリオーダーを指定して値の入れ替えを行う | C++11 C++20から非推奨 C++26で削除

## ハッシュサポート

名前 | 説明 | 対応バージョン
--- | --- | ---
`template <class T> struct hash;` | `hash`クラスの先行宣言 | C++11
`template <class T> struct hash<shared_ptr<T>>;` | `hash`クラスの`shared_ptr`に対する特殊化 | C++11

## 推論補助

名前 | 説明 | 対応バージョン
--- | --- | ---
`(deduction_guide)` | クラステンプレートの推論補助 | C++17

## 例

### shared_ptrの基本的な使い方

    #include <iostream>
    #include <memory>

    int main()
    {
      // newしたポインタをshared_ptrオブジェクトに管理させる
      // 所有者は1人。
      std::shared_ptr<int> p1(new int(3));

      {
        // shared_ptrオブジェクトをコピーすることで、
        // 複数のオブジェクトが一つのリソースを共有できる。
        // 所有者が2人になる。
        std::shared_ptr<int> p2 = p1;

        // 共有しているリソースにアクセスする
        std::cout << *p2 << std::endl;
      } // p2のデストラクタが実行される。
        // リソースの所有者が1人になる。
        // ここではまだ、リソースは解放されない。

      std::cout << *p1 << std::endl;
    } // p1のデストラクタが実行される。
      // リソースの所有者が0人になる。
      // 誰もリソースを参照しなくなったので、リソースが解放される。

#### 出力

    3
    3

### shared_ptr<void>に、あらゆる型のポインタを格納する

`void`をテンプレート引数とする`shared_ptr`に対してどんな型のポインタを代入したとしても、代入した型のデストラクタは、正しく実行される。通常、`void*`に型変換して代入されたポインタは、`delete`演算子を呼んだとしても元の型のデストラクタは呼び出されない。しかし`shared_ptr`の場合は、代入されたポインタの型が持つデストラクタが正しく実行されることが保証される。保証の文面はデストラクタのページを参照。

    #include <iostream>
    #include <memory>

    struct X {
      ~X()
      {
        std::cout << "X dtor" << std::endl;
      }
    };

    struct Y {
      ~Y()
      {
        std::cout << "Y dtor" << std::endl;
      }
    };

    int main()
    {
      std::shared_ptr<void> p(new X());

      std::cout << 0 << std::endl;

      p.reset(new Y()); // Xが破棄される

      std::cout << 1 << std::endl;
    } // Yが破棄される

### 出力

    0
    X dtor
    1
    Y dtor

## バージョン

### 言語

- C++11

### 処理系

- Clang: 3.0 ✅
- GCC: 4.3.6 ✅
- ICC: ??
- Visual C++: 2008 (TR1) ✅, 2010 ✅, 2012 ✅, 2013 ✅

## 関連項目

- `std::enable_shared_from_this`
  - `this`ポインタを`shared_ptr`として使用する場合は、この機能を使用する
- `std::unique_ptr`
  - 所有権を共有する必要がない場合は、この機能を使用する

## 参照

- 動的削除子 (dynamic deleter) - 意外と知られていない？ `boost::shared_ptr` の側面
- P0163R0 `shared_ptr::weak_type`
- P0414R1 Merging `shared_ptr` changes from Library Fundamentals to C++17
- P0619R4 Reviewing deprecated facilities of C++17 for C++20