名前空間
変種
操作

std::shared_ptr::shared_ptr

提供: cppreference.com
< cpp‎ | memory‎ | shared ptr
 
 
 
動的メモリ管理
未初期化記憶域
(C++17)
ガベージコレクションサポート
その他
(C++20)
(C++11)
(C++11)
C のライブラリ
低水準のメモリ管理
 
 
constexpr shared_ptr() noexcept;
(1)
constexpr shared_ptr( std::nullptr_t ) noexcept;
(2)
template< class Y >
explicit shared_ptr( Y* ptr );
(3)
template< class Y, class Deleter >
shared_ptr( Y* ptr, Deleter d );
(4)
template< class Deleter >
shared_ptr( std::nullptr_t ptr, Deleter d );
(5)
template< class Y, class Deleter, class Alloc >
shared_ptr( Y* ptr, Deleter d, Alloc alloc );
(6)
template< class Deleter, class Alloc >
shared_ptr( std::nullptr_t ptr, Deleter d, Alloc alloc );
(7)
template< class Y >
shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;
(8)
shared_ptr( const shared_ptr& r ) noexcept;
(9)
template< class Y >
shared_ptr( const shared_ptr<Y>& r ) noexcept;
(9)
shared_ptr( shared_ptr&& r ) noexcept;
(10)
template< class Y >
shared_ptr( shared_ptr<Y>&& r ) noexcept;
(10)
template< class Y >
explicit shared_ptr( const std::weak_ptr<Y>& r );
(11)
template< class Y >
shared_ptr( std::auto_ptr<Y>&& r );
(12) (C++17で削除)
template< class Y, class Deleter >
shared_ptr( std::unique_ptr<Y,Deleter>&& r );
(13)

管理するオブジェクトを参照する様々なポインタ型から新しい shared_ptr を構築します。

以下の説明において、ポインタ型 Y* がポインタ型 T*互換であるとは、 Y*T* に変換可能である、または、 Y が配列型 U[N] であり TU[] (またはその cv 修飾された型) である、という意味です。

(C++17およびそれ以降)
1-2) 管理対象オブジェクトを持たない、すなわち空の shared_ptr を構築します。
3-7) 管理対象オブジェクトを指すポインタとして ptr を持つ shared_ptr を構築します。

Y*T* に変換可能でなければなりません。

(C++17以前)

T が配列型 U[N] の場合、これらのコンストラクタは、 Y(*)[N]T* に変換可能でなければ、オーバーロード解決に参加しません。 そうでない場合、これらのコンストラクタは、 Y*T* に変換可能でなければ、オーバーロード解決に参加しません。

(C++17およびそれ以降)
さらに、
3) デリータとして delete 式 delete ptr を使用します (C++17以前)T が配列型でなければ delete 式 delete ptr を使用し、 T が配列型であれば delete[] ptr を使用します (C++17およびそれ以降)Y は完全型でなければなりません。 delete 式は well-formed でなければならず、 well-defined な動作を持たねばならず、いかなる例外も投げてはなりません。 さらに、このコンストラクタは、 delete 式が well-formed でない場合、オーバーロード解決に参加しません。 (C++17およびそれ以降)
4-5) デリータとして指定されたデリータ d を使用します。 式 d(ptr) は well-formed でなければならず、 well-defined な動作を持たなければならず、いかなる例外も投げてはなりません。 d の構築および d からの格納されるデリータの構築は例外を投げてはなりません。

DeleterCopyConstructible でなければなりません。

(C++17以前)

さらに、これらのコンストラクタは、式 d(ptr) が well-formed でないか、 std::is_move_constructible<D>::valuefalse である場合、オーバーロード解決に参加しません。

(C++17およびそれ以降)
6-7) (4-5) と同じですが、さらに内部使用のデータ確保のために alloc のコピーを使用します。 AllocAllocator でなければなりません。
8) エイリアシングコンストラクタ。 所有権情報を r と共有する shared_ptr を構築しますが、無関係の管理されていないポインタ ptr を保持します。 この shared_ptr がスコープ外に出る最後のグループの場合、 r によって元々管理されていたオブジェクトに対して、その格納されているデリータが呼ばれます。 しかし、この shared_ptr に対して get() を呼べば、常に ptr のコピーを返します。 この shared_ptr が存在する限りこの ptr が有効あり続けることを保証するのはプログラマの責任です。 一般的なユースケースとしては、 ptrr の管理するオブジェクトのメンバであるとか、 r.get() のエイリアス (つまりダウンキャスト) であるとかです。
9) r によって管理されているオブジェクトの所有権を共有する shared_ptr を構築します。 r の管理しているオブジェクトがなければ、 *this の管理するオブジェクトもありません。 このテンプレートオーバーロードは、 Y*T* に暗黙に変換可能 (C++17以前)互換 (C++17およびそれ以降)でなければ、オーバーロード解決に参加しません。
10) shared_ptrr からムーブ構築します。 構築後、 *thisr のそれまでの状態のコピーを格納し、 r は空になり、その格納されているポインタはNULLになります。 このテンプレートオーバーロードは、 Y*T* に暗黙に変換可能 (C++17以前)互換 (C++17およびそれ以降)でなければ、オーバーロード解決に参加しません。
11) r によって管理されているオブジェクトの所有権を共有する shared_ptr を構築します。 Y*T* に暗黙に変換可能でなければなりません。 (C++17以前)このオーバーロードは、Y*T* と互換である場合にのみ、オーバーロード解決に参加します。 (C++17およびそれ以降) ちなみに、同じ目的に r.lock() を使用することもできます。 違いは、このコンストラクタは引数が空の場合に例外を投げますが、 std::weak_ptr<T>::lock() はその場合に空の std::shared_ptr を構築します。
12) r によって所有されていたオブジェクトを格納し所有する shared_ptr を構築します。 Y*T* に変換可能でなければなりません。 構築後、 r は空になります。
13) r によって現在管理されているオブジェクトを管理する shared_ptr を構築します。 管理対象オブジェクトの将来の削除のために r と紐付くデリータが格納されます。 呼び出し後、 r が管理するオブジェクトはなくなります。
このオーバーロードは、 std::unique_ptr<Y, Deleter>::pointerT*互換でない場合、オーバーロード解決に参加しません。 r.get() がNULLポインタの場合、このオーバーロードはデフォルトコンストラクタ (1) と同等です。 (C++17およびそれ以降)
Deleter が参照型の場合、 shared_ptr(r.release(), std::ref(r.get_deleter()) と同等です。 そうでなければ、 shared_ptr(r.release(), r.get_deleter()) と同等です。

T が配列型でないとき、オーバーロード (3), (4), (6)ptrshared_from_this を有効化し、オーバーロード (13)r.release() によって返されたポインタで shared_from_this を有効化します。

目次

[編集] ノート

コンストラクタが U* 型のポインタ ptrshared_from_this を有効化するとは、 U曖昧でなくアクセス可能な (C++17およびそれ以降) std::enable_shared_from_this の特殊化を基底クラスに持つかどうか調べ、もし持つのであれば以下の文を評価する、という意味です。

if (ptr != nullptr && ptr->weak_this.expired())
  ptr->weak_this = std::shared_ptr<std::remove_cv_t<U>>(*this,
                                  const_cast<std::remove_cv_t<U>*>(ptr));

ただし weak_thisstd::shared_from_this が持つ std::weak_ptr 型の隠された mutable なメンバです。 weak_this メンバの代入はアトミックでなく、同じオブジェクトに対するあらゆる潜在的な並行アクセスと衝突します。 これにより shared_from_this() の将来の呼び出しが、この生のポインタのコンストラクタによって作成された shared_ptr と、所有権を共有することが保証されます。

上記の説明用コード内の判定 ptr->weak_this.expired() は、すでに所有者がある場合に weak_this が再代入されないようにします。 C++17 以降この判定が要求されます。

生のポインタのオーバーロードは、その指す先のオブジェクトの所有権を仮定します。 そのため、 shared_ptr によってすでに管理されているオブジェクトに対して、生のポインタのオーバーロードを使用して shared_ptr を構築すると (shared_ptr(ptr.get()) など)、未定義動作に繋がりがちです。 そのオブジェクトが std::enable_shared_from_this から派生した型であってもです。

デフォルトコンストラクタが constexpr であるため、 static な shared_ptr は、いかなる動的非ローカル初期化が始まるよりも前に、静的非ローカル初期化の一部として初期化されます。 このため、 static オブジェクトのコンストラクタで shared_ptr を使用しても安全です。

C++11 および C++14 では、 std::shared_ptr<T>std::unique_ptr<T[]> からの構築が有効です。

std::unique_ptr<int[]> arr(new int[1]);
std::shared_ptr<int> ptr(std::move(arr));

shared_ptrunique_ptr からそのデリータ (std::default_delete<T[]> オブジェクト) を取得するため、配列は正しく解放されます。

これは C++17 以降できません。 代わりに配列形式の std::shared_ptr<T[]> を使用するべきです。

[編集] 引数

ptr - 管理するオブジェクトを指すポインタ
d - オブジェクトを破棄するために使用するデリータ
alloc - 内部使用のデータ確保のために使用するアロケータ
r - 所有権を共有または取得する別のスマートポインタ

[編集] 例外

3) 要求される追加のメモリが取得できなければ std::bad_alloc。 他のエラーに対して処理系定義の例外を投げるかもしれません。 例外が発生した場合は delete ptr (C++17以前)T が配列型でなければ delete ptr、そうでなければ delete[] ptr (C++17およびそれ以降) が呼ばれます。
4-7) 要求される追加のメモリが取得できなければ std::bad_alloc。 他のエラーに対して処理系定義の例外を投げるかもしれません。 例外が発生した場合は d(ptr) が呼ばれます。
11) r.expired() == true の場合 std::bad_weak_ptr。 この場合、コンストラクタは効果を持ちません。
12) 要求される追加のメモリが取得できなければ std::bad_alloc。 他のエラーに対して処理系定義の例外を投げるかもしれません。 例外が発生した場合、このコンストラクタは効果を持ちません。
13) 例外が発生した場合、コンストラクタは効果を持ちません。

[編集]

#include <memory>
#include <iostream>
 
struct Foo {
    Foo() { std::cout << "Foo...\n"; }
    ~Foo() { std::cout << "~Foo...\n"; }
};
 
struct D { 
    void operator()(Foo* p) const {
        std::cout << "Call delete from function object...\n";
        delete p;
    }
};
 
int main()
{
    {
        std::cout << "constructor with no managed object\n";
        std::shared_ptr<Foo> sh1;
    }
 
    {
        std::cout << "constructor with object\n";
        std::shared_ptr<Foo> sh2(new Foo);
        std::shared_ptr<Foo> sh3(sh2);
        std::cout << sh2.use_count() << '\n';
        std::cout << sh3.use_count() << '\n';
    }
 
    {
        std::cout << "constructor with object and deleter\n";
        std::shared_ptr<Foo> sh4(new Foo, D());
        std::shared_ptr<Foo> sh5(new Foo, [](auto p) {
           std::cout << "Call delete from lambda...\n";
           delete p;
        });
    }
}

出力:

constructor with no managed object
constructor with object
Foo...
2
2
~Foo...
constructor with object and deleter
Foo...
Foo...
Call delete from lambda...
~Foo...
Call delete from function object...
~Foo..

[編集] 関連項目

新しいオブジェクトを管理する shared_ptr を作成します
(関数テンプレート) [edit]
アロケータを使用して確保した新しいオブジェクトを管理する shared_ptr を作成します
(関数テンプレート) [edit]
自身を参照する shared_ptr の作成を可能にします
(クラステンプレート) [edit]