C++スマートポインターと所有権

最終更新: 2024-02-28 10:22:21 +0800 +0800
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

スマートポインターは、インターフェース上で所有権を明示します。ただし、オブジェクトのライフタイムが別の場所で保証されており、単に借用する目的だけで使われる参照や生ポインターを置き換えるものではありません。ライフタイムの契約に基づいてポインター型を選択し、API境界では所有権の移転と観察を明示してください。

一意所有権 #

std::unique_ptr<T> は1つのオブジェクトを所有し、ムーブ専用です。通常の new とデフォルトデリータが適切な場合は std::make_unique で生成し、所有権を移転するには値渡しまたは値返しを使用します。

cpp
#include <memory>

std::unique_ptr<Connection> open_connection(Address address);
void install_connection(std::unique_ptr<Connection> connection);

install_connection(open_connection(address));

カスタムデリータは unique_ptr の型の一部であるため、サイズやAPIが受け付ける型に影響する可能性があります。デリータは所有権プロトコルに対応できなければならず、破棄処理から例外を送出してはなりません。

unique_ptr<T> は、T が不完全型であってもヘッダーに記述できます。ただしデフォルトデリータでは、オブジェクトを破棄する操作がインスタンス化される箇所で T が完全型である必要があります。これは通常、所有クラスのクラス外デストラクタです。unique_ptr<T[]> は配列の確保を表しますが、要素数を保持しません。所有するシーケンスには std::vector<T> を優先してください。

共有所有権と観察 #

std::shared_ptr<T> は、所有権の状態と、通常はデリータおよびアロケーターを含む制御ブロックを共有します。shared_ptr をコピーすると所有権が拡張され、最後の所有ポインターが管理対象オブジェクトを破棄します。std::make_shared はオブジェクトと制御ブロックをまとめて確保できるため、確保回数を減らせます。ただし、weakオブザーバーは制御ブロックを保持するため、この一体化された確保によって、オブザーバーが消滅するまでオブジェクトのストレージが利用できない状態になることがあります。

エイリアシングコンストラクターは、別のポインターを保持しながら既存の制御ブロックを共有します。

cpp
auto owner = std::make_shared<Record>();
std::shared_ptr<Member> member(owner, &owner->member);

member.get() はサブオブジェクトを指しますが、ライフタイムは owner の Record によって管理されます。同じ生ポインターから無関係な shared_ptr インスタンスを構築しないでください。それぞれが、そのオブジェクトを独立して所有していると判断してしまいます。

std::weak_ptr<T> は、オブジェクトのライフタイムを延長せずに制御ブロックを観察します。デリファレンスする前に lock() を使用して、一時的な所有ポインターを取得してください。所有権サイクルによってオブジェクトグラフが無期限に存続してしまう場合は、バックエッジやキャする必要もない操作では const std::shared_ptr<T>& を受け取る方法もあります。ただし、T& または T* を受け取るほうが借用を直接的に文書化できます。借用したポインターまたは参照は、呼び出し元が保証したライフタイムの期間に限って有効です。

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)