Namespaces
Variants

std:: unique_ptr

From cppreference.net
Memory management library
( exposition only* )
Allocators
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Memory resources
Uninitialized storage (until C++20)
( until C++20* )
( until C++20* )
( until C++20* )

Garbage collector support (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
(C++11) (until C++23)
ヘッダーで定義 <memory>
template <

class T,
class Deleter = std:: default_delete < T >

> class unique_ptr ;
(1) (C++11以降)
template <

class T,
class Deleter

> class unique_ptr < T [ ] , Deleter > ;
(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つのバージョンがあります:

  1. 単一のオブジェクトを管理します(例: new で割り当てられたオブジェクト)。
  2. オブジェクトの動的に割り当てられた配列を管理します(例: 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)
単一オブジェクト版、 unique_ptr<T>
管理対象オブジェクトへのポインタを間接参照する
(public member function)
配列版、 unique_ptr<T[]>
管理対象配列へのインデックスアクセスを提供する
(public member function)

非メンバー関数

新しいオブジェクトを管理するuniqueポインタを作成する
(関数テンプレート)
別の unique_ptr または nullptr と比較する
(関数テンプレート)
管理対象ポインタの値を出力ストリームに出力する
(関数テンプレート)
std::swap アルゴリズムを特殊化する
(関数テンプレート)

ヘルパークラス

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 型のインスタンスを保持するオブジェクト
(クラス)