std:: unique_ptr
|
ヘッダーで定義
<memory>
|
||
|
template
<
class
T,
|
(1) | (C++11以降) |
|
template
<
class
T,
|
(2) | (C++11以降) |
std::unique_ptr
は、ポインタを介して別のオブジェクトを所有(責任を持って管理)し、
unique_ptr
がスコープ外に出たときにそのオブジェクトを破棄するスマートポインタです。
オブジェクトは、以下のいずれかの状況が発生した際に関連付けられたデリータを使用して破棄されます:
-
管理している
unique_ptrオブジェクトが破棄されたとき。 -
管理している
unique_ptrオブジェクトが operator= または reset() によって別のポインタが代入されたとき。
オブジェクトは、ユーザーが指定した可能性のあるデリーターを使用して、
get_deleter
(
)
(
ptr
)
を呼び出すことで破棄されます。デフォルトのデリーター(
std::default_delete
)は
delete
演算子を使用し、これがオブジェクトを破棄してメモリを解放します。
A
unique_ptr
はオブジェクトを所有していない場合もあり、その状態は
空
と表現されます。
unique_ptr
には2つのバージョンがあります:
- 単一のオブジェクトを管理します(例: new で割り当てられたオブジェクト)。
- オブジェクトの動的に割り当てられた配列を管理します(例: new [ ] で割り当てられた配列)。
このクラスは MoveConstructible および MoveAssignable の要件を満たすが、 CopyConstructible および CopyAssignable の要件は満たさない。
T*
が有効な型でない場合(例えば、
T
が参照型である場合)、
std
::
unique_ptr
<
T, Deleter
>
の定義をインスタンス化するプログラムは不適格です。
| 型要件 | ||
-
Deleter
は
FunctionObject
または
FunctionObject
への左辺値参照、または関数への左辺値参照であり、
unique_ptr
<
T, Deleter
>
::
pointer
型の引数で呼び出し可能でなければならない。
|
目次 |
注記
非constの
unique_ptr
のみが、管理対象オブジェクトの所有権を別の
unique_ptr
に転送できます。オブジェクトの寿命が
const
std
::
unique_ptr
によって管理されている場合、そのオブジェクトの寿命はポインタが作成されたスコープに限定されます。
unique_ptr
は一般的に、以下のようなオブジェクトのライフタイム管理に使用されます:
- 動的寿命を持つオブジェクトを扱うクラスと関数に例外安全性を提供し、通常終了時と例外による終了時の両方で削除が保証されます。
- 動的寿命を持つ一意所有オブジェクトの所有権を関数に渡すこと。
- 動的寿命を持つユニーク所有オブジェクトを関数から取得する。
- 動的に割り当てられたオブジェクトへのポインタを保持する移動対応コンテナ(例:多態性の動作が望まれる場合)の要素型として、 std::vector などで使用されます。
unique_ptr
は
不完全型
T
に対して構築可能であり、
pImplイディオム
におけるハンドルとしての使用を容易にします。デフォルトデリータを使用する場合、
T
はデリータが呼び出される時点(
unique_ptr
のデストラクタ、ムーブ代入演算子、
reset
メンバ関数内で発生)で完全型である必要があります。(対照的に、
std::shared_ptr
は不完全型への生ポインタから構築できませんが、
T
が不完全な状態で破棄可能です)。
T
がクラステンプレートの特殊化である場合、
unique_ptr
を被演算子として使用する際(例:
!
p
)には、
ADL
により
T
のテンプレートパラメータが完全型であることが要求されることに注意してください。
T
が何らかの基底クラス
B
の
derived class
である場合、
unique_ptr
<
T
>
は
unique_ptr
<
B
>
へ
implicitly convertible
です。結果の
unique_ptr
<
B
>
のデフォルト削除子は
B
に対して
operator delete
を使用するため、
B
のデストラクタが
virtual
でない限り
undefined behavior
を引き起こします。
std::shared_ptr
の動作は異なることに注意してください:
std::
shared_ptr
<
B
>
は型
T
に対する
operator delete
を使用し、
B
のデストラクタが
virtual
でなくても所有オブジェクトは正しく削除されます。
std::shared_ptr
とは異なり、
unique_ptr
は
NullablePointer
を満たす任意のカスタムハンドル型を通じてオブジェクトを管理できます。これにより、例えば、
typedef
boost::offset_ptr
pointer;
を定義する
Deleter
を提供することで、共有メモリ内に配置されたオブジェクトの管理が可能になります。あるいは、他の
fancy pointer
を使用することもできます。
| 機能テスト マクロ | 値 | 標準 | 機能 |
|---|---|---|---|
__cpp_lib_constexpr_memory
|
202202L
|
(C++23) |
constexpr
std::unique_ptr
|
ネスト型
| 型 | 定義 |
| pointer |
std::
remove_reference
<
Deleter
>
::
type
::
pointer
が存在する場合はその型、それ以外の場合は
T*
。
NullablePointer
要件を満たさなければならない
|
| element_type |
T
、この
unique_ptr
によって管理されるオブジェクトの型
|
| deleter_type |
Deleter
、デストラクタから呼び出される関数オブジェクト、または関数/関数オブジェクトへの左辺値参照
|
メンバー関数
新しい
unique_ptr
を構築する
(public member function) |
|
|
管理対象オブジェクトが存在する場合、それを破棄する
(public member function) |
|
unique_ptr
を代入する
(public member function) |
|
修飾子 |
|
|
管理対象オブジェクトへのポインタを返し、所有権を解放する
(public member function) |
|
|
管理対象オブジェクトを置き換える
(public member function) |
|
|
管理対象オブジェクトを交換する
(public member function) |
|
オブザーバ |
|
|
管理対象オブジェクトへのポインタを返す
(public member function) |
|
|
管理対象オブジェクトの破棄に使用されるデリータを返す
(public member function) |
|
|
関連付けられた管理対象オブジェクトが存在するかどうかをチェックする
(public member function) |
|
単一オブジェクト版、
|
|
|
管理対象オブジェクトへのポインタを間接参照する
(public member function) |
|
配列版、
|
|
|
管理対象配列へのインデックスアクセスを提供する
(public member function) |
|
非メンバー関数
|
(C++14)
(C++20)
|
新しいオブジェクトを管理するuniqueポインタを作成する
(関数テンプレート) |
|
(C++20で削除)
(C++20)
|
別の
unique_ptr
または
nullptr
と比較する
(関数テンプレート) |
|
(C++20)
|
管理対象ポインタの値を出力ストリームに出力する
(関数テンプレート) |
|
(C++11)
|
std::swap
アルゴリズムを特殊化する
(関数テンプレート) |
ヘルパークラス
|
(C++11)
|
std::unique_ptr
のハッシュサポート
(クラステンプレートの特殊化) |
例
#include <cassert> #include <cstdio> #include <fstream> #include <iostream> #include <locale> #include <memory> #include <stdexcept> // 以下のランタイムポリモーフィズムのデモ用ヘルパークラス struct B { virtual ~B() = default; virtual void bar() { std::cout << "B::bar\n"; } }; struct D : B { D() { std::cout << "D::D\n"; } ~D() { std::cout << "D::~D\n"; } void bar() override { std::cout << "D::bar\n"; } }; // unique_ptrを消費する関数は、値渡しまたは右辺値参照で受け取ることができる std::unique_ptr<D> pass_through(std::unique_ptr<D> p) { p->bar(); return p; } // カスタムデリーターのデモ用ヘルパー関数(下記参照) void close_file(std::FILE* fp) { std::fclose(fp); } // unique_ptr ベースのリンクリスト デモ struct List { struct Node { int data; std::unique_ptr<Node> next; }; std::unique_ptr<Node> head; ~List() { // ループ内でリストノードを順次破棄する、デフォルトのデストラクタ // その「next」のデストラクタを再帰的に呼び出していたであろう、それは // 十分に大きなリストに対してスタックオーバーフローを引き起こす。 while (head) { auto next = std::move(head->next); head = std::move(next); } } void push(int data) { head = std::unique_ptr<Node>(new Node{data, std::move(head)}); } }; int main() { std::cout << "1) ユニーク所有権セマンティクスのデモ\n"; { // (ユニーク所有権を持つ) リソースを作成 std::unique_ptr<D> p = std::make_unique<D>(); // 所有権を "pass_through" に転送します, // その後、戻り値を介して所有権を戻す std::unique_ptr<D> q = pass_through(std::move(p)); // 「p」は現在ムーブ後(moved-from)の「空」状態であり、nullptrと等しい assert(!p); } std::cout << "\n" "2) ランタイムポリモーフィズムのデモ\n"; { // 派生リソースを作成し、基本型を介してそれを指す std::unique_ptr<B> p = std::make_unique<D>(); // 動的ディスパッチは期待通りに動作する p->bar(); } std::cout << "\n" "3) カスタムデリーターデモ\n"; std::ofstream("demo.txt") << 'x'; // 読み込むファイルを準備 { using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>; unique_file_t fp(std::fopen("demo.txt", "r"), &close_file); if (fp) std::cout << char(std::fgetc(fp.get())) << '\n'; } // 「close_file()」がここで呼び出される(「fp」がnullでない場合) std::cout << "\n" "4) カスタムラムダ式デリータと例外安全性デモ\n"; try { std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr) { std::cout << "カスタムデリーターからの破棄...\n"; delete ptr; }); throw std::runtime_error(""); // 「p」がプレーン・ポインタの場合、ここでリークする } catch (const std::exception&) { std::cout << "例外をキャッチしました\n"; } std::cout << "\n" "5) unique_ptrの配列形式デモ\n"; { std::unique_ptr<D[]> p(new D[3]); } // 「D::~D()」は3回呼び出されます std::cout << "\n" "6) リンクリスト デモ\n"; { List wall; const int enough{1'000'000}; for (int beer = 0; beer != enough; ++beer) wall.push(beer); std::cout.imbue(std::locale("en_US.UTF-8")); std::cout << enough << " ビールの瓶が壁に...\n"; } // すべてのビールを破棄する }
出力例:
1) ユニーク所有権セマンティクスのデモ D::D D::bar D::~D 2) 実行時ポリモーフィズムのデモ D::D D::bar D::~D 3) カスタムデリーターのデモ x 4) カスタムラムダ式デリーターと例外安全性のデモ D::D カスタムデリーターからの破棄中... D::~D 例外をキャッチしました 5) unique_ptrの配列形式のデモ D::D D::D D::D D::~D D::~D D::~D 6) リンクリストのデモ 1,000,000本のビールが壁に...
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| LWG 4144 | C++11 |
T*
が有効な型を形成する必要はなかった
|
必要 |
関連項目
|
(C++11)
|
共有オブジェクト所有権セマンティクスを持つスマートポインタ
(クラステンプレート) |
|
(C++11)
|
std::shared_ptr
によって管理されるオブジェクトへの弱参照
(クラステンプレート) |
|
(C++26)
|
値ライクなセマンティクスを持つ動的に割り当てられたオブジェクトを含むラッパー
(クラステンプレート) |
|
(C++17)
|
任意の
CopyConstructible
型のインスタンスを保持するオブジェクト
(クラス) |